<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Nizar&#39;s Blog</title>
  <subtitle>I share my thoughts and ideas on new technologies I encounter, new findings and everything and anything that I find helpful or interesting</subtitle>
  <link href="https://nizar.se/feed.xml" rel="self"/>
  <link href="https://nizar.se/"/>
  <updated>2025-12-01T00:00:00Z</updated>
  <id>https://nizar.se/</id>
  <author>
    <name>Nizar</name>
  </author>
  <entry>
    <title>The Code is the Context</title>
    <link href="https://nizar.se/the-code-is-the-context/"/>
    <updated>2025-12-01T00:00:00Z</updated>
    <id>https://nizar.se/the-code-is-the-context/</id>
    <link rel="enclosure" type="image/jpeg" href="https://nizar.se/uploads/lighthouse.jpg" />
    <content type="html">
      &lt;img src="https://nizar.se/uploads/lighthouse.jpg" alt="Close-up of a lighthouse lantern room with glass panels and metal railing, symbolizing navigation and timeless guidance" /&gt;
      &lt;p&gt;Most advice on working with agents focuses on orchestration and interaction strategies. But I keep
finding renewed significance in the software development fundamentals we&#39;ve always known. After all,
agents don&#39;t just respond to how we prompt them, they also respond to what they find in the
codebase.&lt;/p&gt;
&lt;h2&gt;Discovery&lt;/h2&gt;
&lt;p&gt;Agents start each session fresh, with no memory of previous work, just the prompt and whatever
context files we provide. So they search, read, and infer, assembling context from what they find.&lt;/p&gt;
&lt;p&gt;This discovery process is constant. When writing a test, they search for patterns to follow. When a
fix fails, they explore to understand why. When preparing a commit message, they read changes to
summarize intent.&lt;/p&gt;
&lt;p&gt;You can shape discovery through how you interact with and orchestrate the agents:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Delegation&lt;/strong&gt; keeps the main context clean. Subagents handle exploration and return only what&#39;s
relevant.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Progressive disclosure&lt;/strong&gt; provides information just-in-time rather than front-loading everything.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Feedback loops&lt;/strong&gt; catch mistakes early. The faster agents can verify their work through tests,
type checks, and linting, the less they diverge.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I cover these in my
&lt;a href=&quot;https://factor10.com/news/on-demand-webinar-5-pro-tips-from-developing-and-using-tdd-guard/&quot;&gt;TDD Guard webinar&lt;/a&gt;.
But interaction strategies have limits. The deeper factor is the codebase itself: unclear code
forces more searching, disorganized systems lead to false assumptions, and complexity requires
lengthy explanations.&lt;/p&gt;
&lt;h2&gt;What&#39;s Old Becomes New Again&lt;/h2&gt;
&lt;p&gt;When you work closely with a codebase for months or years, you develop home blindness. The
convoluted function that &amp;quot;works fine&amp;quot;. The abstraction that made sense at the time. The naming
obvious to you but obscure to anyone else.&lt;/p&gt;
&lt;p&gt;Agents don&#39;t have your context. They see the code as it is, not as you remember it.&lt;/p&gt;
&lt;p&gt;Watch where they search repeatedly for the same concept. Notice when they misunderstand what a
function does despite reading it. Pay attention when they need long explanations to understand
concepts and constraints the code should express.&lt;/p&gt;
&lt;p&gt;That friction is information. It points to familiar territory:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Self-documenting code&lt;/strong&gt; means less searching. When the functions and variables reveal their
intent, agents don&#39;t need to trace through their implementations.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Single responsibility&lt;/strong&gt; means fewer surprises. When a function does one thing, assumptions hold.
Fewer surprises means less recovery and backtracking.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Simplicity&lt;/strong&gt; means faster reasoning. Complex solutions require more context to understand. The
less there is to infer, the faster discovery completes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tests&lt;/strong&gt; serve as executable documentation. Well-written tests tell agents what the code should
do without requiring archaeology.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These aren&#39;t new. Agents make them visible in a new way.&lt;/p&gt;
&lt;h2&gt;Closing Thoughts&lt;/h2&gt;
&lt;p&gt;This isn&#39;t a call to refactor your entire codebase. It&#39;s an invitation to notice what the agents
reveal, then act on it where it matters. The changes that help agents discover faster also make code
easier to review, reason about, and maintain.&lt;/p&gt;
&lt;p&gt;Thanks to my colleagues at &lt;a href=&quot;https://factor10.com/&quot;&gt;factor10&lt;/a&gt; for the conversations that shaped these
ideas, especially &lt;a href=&quot;https://jimmynilsson.com/&quot;&gt;Jimmy Nilsson&lt;/a&gt;, whose insight that &amp;quot;friction is
information&amp;quot; became central to this piece.&lt;/p&gt;

    </content>
  </entry>
  <entry>
    <title>Lean Claude Code for Production</title>
    <link href="https://nizar.se/lean-claude-code-for-production/"/>
    <updated>2025-08-15T00:00:00Z</updated>
    <id>https://nizar.se/lean-claude-code-for-production/</id>
    <link rel="enclosure" type="image/jpeg" href="https://nizar.se/uploads/scaffolding.jpg" />
    <content type="html">
      &lt;img src="https://nizar.se/uploads/scaffolding.jpg" alt="Multi-level scaffolding with intersecting stairs and beams, evoking structured workflows and support systems" /&gt;
      &lt;p&gt;Many agentic coding demos showcase landing pages, one-off scripts, or greenfield projects. While
technically impressive, they often produce single files with little thought for maintainability.
Even OpenAI&#39;s ChatGPT 5 launch demo followed this pattern. At the other extreme, some content
focuses almost entirely on elaborate integrations and orchestrations.&lt;/p&gt;
&lt;p&gt;Both have their place, but neither reflect how I ship production code with agents. That gap in
middle-ground coverage feeds two common misconceptions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AI-generated code cannot meet disciplined, production-grade standards.&lt;/li&gt;
&lt;li&gt;Agentic coding is inherently complex and needs heavy upfront investment.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&#39;s the middle path I use in real projects. Simple setup, clear guardrails, deliberate steering,
and no ceremony.&lt;/p&gt;
&lt;h2&gt;Project Setup&lt;/h2&gt;
&lt;p&gt;Claude Code keeps project context and details in &lt;code&gt;CLAUDE.md&lt;/code&gt;, usually created with the &lt;code&gt;/init&lt;/code&gt;
command when you first start working on a project. A common trap I&#39;ve fallen into myself is stuffing
it with every rule and best practice. It feels logical. You want the agent to &amp;quot;know everything&amp;quot;
upfront, but in practice, it often backfires.&lt;/p&gt;
&lt;p&gt;When the file contains many goals and constraints at the same level, the model struggles to
prioritize. This isn&#39;t forgetfulness—it&#39;s how large language models work when instructions compete
for attention.&lt;/p&gt;
&lt;p&gt;This increases inconsistency and makes behavior feel frustratingly unreliable.&lt;/p&gt;
&lt;p&gt;What works for me is keeping &lt;code&gt;CLAUDE.md&lt;/code&gt; lean, ideally under 100 lines, focusing on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The project&#39;s context, purpose, and tech stack&lt;/li&gt;
&lt;li&gt;A brief project structure&lt;/li&gt;
&lt;li&gt;Common scripts to run&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&#39;s roughly what I include:&lt;/p&gt;
&lt;pre class=&quot;language-md&quot;&gt;&lt;code class=&quot;language-md&quot;&gt;&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;#&lt;/span&gt; Project Name&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;A brief description of what this project does.&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;##&lt;/span&gt; Structure&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; src/validators/      # Input validation patterns&lt;br /&gt;&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; src/middlewares/     # Express middleware&lt;br /&gt;&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; src/utils/           # Shared utilities and helpers&lt;br /&gt;&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; test/factories/      # Test data factories&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;##&lt;/span&gt; Commands&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;npm run test           # Run all tests&lt;br /&gt;npm run test:unit      # Run unit tests only&lt;br /&gt;npm run lint           # Check code quality&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This lean file helps the agent with things it typically struggles with or would waste time and
tokens figuring out repeatedly:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Understanding the domain and aligning execution with the project&#39;s purpose&lt;/li&gt;
&lt;li&gt;Avoiding costly full-codebase scans to find existing interfaces, implementations, and helpers&lt;/li&gt;
&lt;li&gt;Knowing which scripts to run without having to look them up each time&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This isn&#39;t about lowering your coding standards: abandoning design patterns, functional programming
principles, or testing requirements. It&#39;s about enforcing these standards through guardrails rather
than bloated instructions.&lt;/p&gt;
&lt;h2&gt;Devcontainers&lt;/h2&gt;
&lt;p&gt;Even in a simple setup, &lt;a href=&quot;https://docs.anthropic.com/en/docs/claude-code/devcontainer&quot;&gt;devcontainers&lt;/a&gt;
are worth it. They provide a consistent, reproducible, and isolated environment with all project
dependencies pre-installed and pre-configured.&lt;/p&gt;
&lt;p&gt;They prevent clashes between system and project dependencies and can gate network access with a
whitelist firewall.&lt;/p&gt;
&lt;h2&gt;Code Quality&lt;/h2&gt;
&lt;h3&gt;Test-Driven Development&lt;/h3&gt;
&lt;p&gt;The biggest quality gain comes from enforcing strict Test-Driven Development (TDD):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Write a failing test first.&lt;/li&gt;
&lt;li&gt;Write the minimal code to pass.&lt;/li&gt;
&lt;li&gt;Refactor while keeping tests green.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Agents are good at producing code quickly. They are less consistent at sequencing work. TDD supplies
the sequence. It also gives short, objective feedback loops that the agent can reason about.&lt;/p&gt;
&lt;p&gt;Without this structure, agents tend to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Jump straight to implementation code&lt;/li&gt;
&lt;li&gt;Write all tests at once&lt;/li&gt;
&lt;li&gt;Skip test runs&lt;/li&gt;
&lt;li&gt;Skip the refactoring step&lt;/li&gt;
&lt;li&gt;Implement more than the current test requires&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The result is untested code, poor design decisions, over-engineering, and technical debt.&lt;/p&gt;
&lt;p&gt;To make TDD non-negotiable, I built &lt;a href=&quot;https://github.com/nizos/tdd-guard&quot;&gt;TDD-Guard&lt;/a&gt; for Claude Code.
It blocks violations such as implementing without a failing test, adding multiple tests at once, or
over-implementing.&lt;/p&gt;
&lt;p&gt;Beyond TDD, it can enforce linting rules, like strict functional programming patterns, ensuring the
agent follows your coding standards automatically.&lt;/p&gt;
&lt;p&gt;With these rules enforced automatically, I focus on the problem and the design instead of policing
process. TDD itself encourages better design, thorough test coverage, and creates living
documentation of your codebase.&lt;/p&gt;
&lt;h3&gt;Linting, Formatting, and Commits&lt;/h3&gt;
&lt;p&gt;Similarly, I use &lt;a href=&quot;https://github.com/typicode/husky&quot;&gt;husky&lt;/a&gt; with
&lt;a href=&quot;https://github.com/lint-staged/lint-staged&quot;&gt;lint-staged&lt;/a&gt; to automatically lint and format code
before commits. With &lt;a href=&quot;https://github.com/conventional-changelog/commitlint&quot;&gt;commitlint&lt;/a&gt;, I enforce
conventional commit messages. This frees up more context and produces more consistent behavior.&lt;/p&gt;
&lt;h2&gt;Planning Work&lt;/h2&gt;
&lt;p&gt;Claude Code&#39;s planning mode is where I usually start. Here, the agent focuses on gathering
information and mapping out the steps to complete a task.&lt;/p&gt;
&lt;p&gt;The key is to be deliberate and explicit in your instructions, while pointing it to the files and
references it needs. Instead of verbose guidelines on testing and design, I show it an existing,
well-structured component and its tests as an example.&lt;/p&gt;
&lt;p&gt;When the plan is ready, I don&#39;t obsess over perfection. The real value is in the context the agent
has gathered. I only intervene at this stage if it clearly missed an important aspect or if I spot
signs of over-engineering. It&#39;s usually more effective to address issues as they arise rather than
front-loading all corrections.&lt;/p&gt;
&lt;p&gt;Finally, I rarely use auto-accept mode. Even though it can be faster, manually approving or steering
each step gives me more control and helps catch small deviations before they snowball.&lt;/p&gt;
&lt;h2&gt;Managing Context&lt;/h2&gt;
&lt;p&gt;Models have a limited context window—think of it as their working memory. As it fills up,
performance gradually degrades.&lt;/p&gt;
&lt;p&gt;Planning mode is excellent for gathering context without overloading the main agent with irrelevant
details. It can delegate investigation to subagents, which read the relevant files, filter out
noise, and pass back only the important findings.&lt;/p&gt;
&lt;p&gt;This keeps the main agent&#39;s context lean and focused. You&#39;ll see Claude Code using this strategy
when it performs a &lt;code&gt;Task&lt;/code&gt;. You can use the same strategy in any mode by simply asking it to use a
subagent to do any investigation work you need.&lt;/p&gt;
&lt;p&gt;Even with this strategy, you&#39;ll eventually reach the limit. When that happens, Claude Code will
offer to compact the context, replacing it with a summary.&lt;/p&gt;
&lt;p&gt;The problem is that summaries aren&#39;t perfect. They sometimes prioritize the wrong things or leave
out critical details.&lt;/p&gt;
&lt;p&gt;This is especially true when priorities shift mid-session. For example, you might spend most of the
session on trial-and-error, then pivot after a breakthrough. If the compacted summary still focuses
on the earlier, discarded work, the agent&#39;s future decisions will be skewed.&lt;/p&gt;
&lt;p&gt;To avoid this, I give custom instructions when triggering &lt;code&gt;/compact&lt;/code&gt;, telling the agent exactly
which details to preserve. This keeps the session better aligned with the findings I value.&lt;/p&gt;
&lt;p&gt;Sometimes my work spans multiple sessions, or I&#39;ve built up a context I want to preserve for later.
In these cases, I ask the agent to save the current context or findings to a temporary markdown
file, essentially a session-specific &lt;code&gt;CLAUDE.md&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Before we finish, I often have the agent propose updates to this document based on our progress or
new findings. This quick review step removes noise, clarifies ambiguous points, and ensures the
saved version captures only what&#39;s worth carrying forward.&lt;/p&gt;
&lt;p&gt;In the next session, I point the agent to that file and have it read it in full, followed by
gathering any additional information it needs. This approach avoids relying on compaction summaries
and gives a clean, intentional handoff between sessions.&lt;/p&gt;
&lt;h2&gt;Bottom Line&lt;/h2&gt;
&lt;p&gt;I&#39;ve been using this setup for the last couple of months, and I&#39;m very happy with the results.&lt;/p&gt;
&lt;p&gt;Custom agents, personas, MCPs, and orchestration can help in specific cases. You most likely don&#39;t
need them to start, especially if your main objective is business value and software quality.&lt;/p&gt;
&lt;p&gt;Prompt optimization has limited return here, especially when you already know the outcome you want.
The bigger gains come from practice and building intuition for effectively interacting with agents.&lt;/p&gt;
&lt;p&gt;For me, the formula is simple:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Be deliberate and explicit about what you want to achieve.&lt;/li&gt;
&lt;li&gt;Give the agent an efficient way to find the information it needs.&lt;/li&gt;
&lt;li&gt;Point it towards relevant examples of the approach you want it to follow.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If work drifts, stop it early, explain the correction, and continue. Claude Code also lets you press
&lt;code&gt;Escape&lt;/code&gt; twice to roll back to a previous point in the session.&lt;/p&gt;
&lt;p&gt;No elaborate orchestration needed—just lean, deliberate practice.&lt;/p&gt;

    </content>
  </entry>
  <entry>
    <title>TDD Guard for Claude Code</title>
    <link href="https://nizar.se/tdd-guard-for-claude-code/"/>
    <updated>2025-07-21T00:00:00Z</updated>
    <id>https://nizar.se/tdd-guard-for-claude-code/</id>
    <link rel="enclosure" type="image/jpeg" href="https://nizar.se/uploads/industrial-machine.jpg" />
    <content type="html">
      &lt;img src="https://nizar.se/uploads/industrial-machine.jpg" alt="Close-up of interlocking metal gears in an industrial machine" /&gt;
      &lt;p&gt;Claude Code fit well into my workflow, but sticking to Test-Driven Development (TDD) principles
still needed occasional reminders: one test at a time, fail first, no over-implementation. It
worked, but it wasn’t effortless. So I built &lt;a href=&quot;https://github.com/nizos/tdd-guard&quot;&gt;TDD Guard&lt;/a&gt;, a
utility that handles that for me and keeps my attention focused on designing solutions rather than
policing TDD.&lt;/p&gt;
&lt;h2&gt;Leveraging Hooks&lt;/h2&gt;
&lt;p&gt;The breakthrough occurred when Anthropic announced
&lt;a href=&quot;https://docs.anthropic.com/en/docs/claude-code/hooks&quot;&gt;Hooks&lt;/a&gt; for Claude Code—coincidentally, the
very day I was seeking a better solution. Hooks automatically execute commands based on predefined
conditions, such as before or after an agent’s action, making them ideal for enforcing coding
standards.&lt;/p&gt;
&lt;p&gt;I began by creating a hook that intercepts all file modification operations before execution,
triggering validation checks for common TDD violations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Implementing functionality without a relevant failing test&lt;/li&gt;
&lt;li&gt;Implementing more than necessary to pass a test&lt;/li&gt;
&lt;li&gt;Adding more than one test at a time&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The validator integrates hook event data, the agent’s current todo list, and the latest test run
output. It then invokes a separate Claude Code session to verify adherence to TDD principles.&lt;/p&gt;
&lt;p&gt;Since Claude Code hooks run as separate processes, TDD Guard persists context data to files between
each phase. This approach allows different hooks, like TDD validation before a change and lint
checks after, to access shared state without relying on complex inter-process communication. It
keeps the system reliable and easy to reason about.&lt;/p&gt;
&lt;p&gt;If no violations are detected, the hook proceeds without interference. But when a violation is
found, it blocks the action and returns feedback clearly stating the issues, along with corrective
guidance.&lt;/p&gt;
&lt;video controls=&quot;&quot; width=&quot;100%&quot; class=&quot;blog-video&quot;&gt;
  &lt;source src=&quot;https://nizar.se/uploads/videos/tdd-guard-demo.mp4&quot; type=&quot;video/mp4&quot; /&gt;
  Your browser does not support the video tag.
&lt;/video&gt;
&lt;h2&gt;Dogfooding the Development&lt;/h2&gt;
&lt;p&gt;With the prototype integrated directly into my workflow, the improvements were immediate.
Eliminating manual reminders was a refreshing change. But the agent&#39;s behavior initially felt too
compliant. I began to suspect this wasn&#39;t due to the validation logic itself, but rather because the
agent had absorbed all the TDD-related terminology present throughout the project—things like test
names, helper functions, and prompt documents.&lt;/p&gt;
&lt;p&gt;It seemed to follow TDD principles simply because the surrounding context steered it that way, not
because enforcement was actually working.&lt;/p&gt;
&lt;p&gt;To properly assess the enforcement, I needed to see how the system behaved outside a TDD-saturated
environment. Testing it in an unrelated project confirmed my suspicion. Some clear violations
slipped through, while valid actions were mistakenly blocked, sometimes prompting humorous attempts
by the agent to circumvent restrictions using terminal commands.&lt;/p&gt;
&lt;h2&gt;Integration Testing&lt;/h2&gt;
&lt;p&gt;That prompted me to invest in robust integration tests. I implemented comprehensive test data
factories covering various scenarios:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Empty, in-progress, completed, or irrelevant todo lists&lt;/li&gt;
&lt;li&gt;Diverse test outputs, including empty, irrelevant passes, and various failure types&lt;/li&gt;
&lt;li&gt;Modifications including minimal implementations, excessive functionality, multiple tests, and
diverse refactoring cases&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This strategy enabled easy adjustments to data structures and facilitated quick support for new
languages like Python without extensive test rewrites. These tests also accommodated Claude Code’s
distinct modification tools: Write, Edit, and MultiEdit.&lt;/p&gt;
&lt;h2&gt;Context Engineering&lt;/h2&gt;
&lt;p&gt;Each of Claude Code&#39;s file operation tools behaves differently. Write generates complete file
contents, while Edit and MultiEdit apply targeted modifications to existing code. These differences
made static prompts feel inefficient and misaligned across many cases.&lt;/p&gt;
&lt;p&gt;One-size-fits-all prompts often led to confusing or conflicting behavior, especially when only some
context was relevant to the operation. For example, Edit or MultiEdit might attempt to introduce
three tests, two of which already existed and were simply refactored. In such cases, the prompt
needed to include guidance for identifying genuinely new tests. But the same guidance would be
irrelevant for a Write operation, which always starts from a clean state.&lt;/p&gt;
&lt;p&gt;To address this, I built a dynamic system that assembles only the relevant instruction modules based
on the operation type and situation. This ensures the model receives clear, concise context tailored
to the task at hand.&lt;/p&gt;
&lt;h2&gt;Multi-Model Support&lt;/h2&gt;
&lt;p&gt;As test complexity increased, slow feedback loops began to limit how quickly I could iterate. To
speed things up, I added a new validation client that runs prompts directly against Anthropic&#39;s API,
bypassing the Claude Code CLI. This made integration tests faster and more practical in CI
workflows. It also gave me the flexibility to experiment with different models to balance cost,
speed, and performance.&lt;/p&gt;
&lt;p&gt;This setup also exposed a few practical challenges. Some models included verbose explanations or
inline code before finalizing an answer, which tripped up the parser and caused false positives. TDD
was a big help here too. I could reliably reproduce the bug before making any fixes, which made it
easy to confirm that the parser now handles that behavior correctly.&lt;/p&gt;
&lt;h2&gt;Rules vs. Mindset&lt;/h2&gt;
&lt;p&gt;Despite improvements, scenario tests still exhibited inconsistencies due to subjective model
interpretations of TDD principles, notably during refactoring. While explicit rule enforcement
resolved test inconsistencies, it only achieved mechanical adherence that did not translate into
improved software quality.&lt;/p&gt;
&lt;p&gt;I discovered that without explicit guidance, agents naturally skip the refactoring phase of the
red-green-refactor cycle or at best make only superficial changes. To understand this better, I had
Claude Code implement a shopping cart using only TDD Guard&#39;s blocking mechanism, without any
instructions about software quality or testing practices. The results were telling: while the guard
successfully enforced test-first development, the resultant code still suffered from tight coupling,
duplication, and poor overall design. This drove home that TDD&#39;s value comes from the mindset and
discipline it instills, not from mechanical rule-following.&lt;/p&gt;
&lt;p&gt;Inspired by my mentor, Per at factor10, who recently shared
&lt;a href=&quot;https://programmaticallyspeaking.com/a-tdd-mindset.html&quot;&gt;reflections on this topic&lt;/a&gt;, I began
exploring how to encourage a genuine TDD mindset. Could aspects of this mindset be emulated using
hooks?&lt;/p&gt;
&lt;h2&gt;Meaningful Refactoring&lt;/h2&gt;
&lt;p&gt;Initially, I considered employing a reviewing model to suggest meaningful refactorings. However,
lacking sufficient system-wide context, this approach risked inadvertently increasing complexity
rather than simplifying the solution, a common problem with local rather than global optimization.
Providing comprehensive context to the model proved both impractical and prohibitively expensive.&lt;/p&gt;
&lt;p&gt;Instead, I integrated lightweight linting tools such as Sonar to identify complexities and code
standard violations, prompting refactoring tasks.&lt;/p&gt;
&lt;p&gt;Unfortunately, post-action hooks were weakly enforced, frequently resulting in deferred or ignored
refactoring tasks. To strengthen enforcement, I stored identified issues, mandating resolution in
subsequent pre-action validation phases. Deliberately withholding specific issue details initially
encouraged the agent to attempt meaningful refactorings independently. Persistent issues were later
explicitly communicated as feedback.&lt;/p&gt;
&lt;h2&gt;Balancing Art and Science&lt;/h2&gt;
&lt;p&gt;Defining &amp;quot;meaningful refactoring&amp;quot; remains inherently subjective and context-dependent, with varying
interpretations of quality standards, design principles, and complexity among developers and teams.
Finding practical tools to flag unnecessary complexity proved trickier than expected. Most are
either correlated with line count or require extensive setup that makes them impractical.&lt;/p&gt;
&lt;p&gt;Moreover, automated linting rules primarily encouraged superficial changes, such as smaller function
sizes, rather than coherent functionality. Recognizing this limitation, I concluded TDD Guard should
enforce basic linting rules during refactoring cycles while leaving deeper, meaningful design
considerations to the developers themselves. While the hook improves results, the system-thinking
and design awareness that human developers bring cannot be matched. After all, engaging actively in
system design and architecture remains one of programming&#39;s most enjoyable aspects.&lt;/p&gt;
&lt;h2&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;The TDD Guard project began two weeks ago during a relaxed, collaborative yearly event, a BBQ at
&lt;a href=&quot;https://jimmynilsson.com/&quot;&gt;Jimmy&lt;/a&gt;’s place with colleagues from
&lt;a href=&quot;https://www.factor10.com/&quot;&gt;factor10&lt;/a&gt;. The initial prototype, a simple “cat detector” blocking
modifications containing “mew”, served as a quick validation of core concepts.&lt;/p&gt;
&lt;p&gt;I intentionally retained these early explorations in the project’s history as a testament to
something I deeply believe in: that joy, authenticity, meaningful companionship, and psychological
safety nurture random curiosity and creativity into tangible innovations.&lt;/p&gt;
&lt;p&gt;Applying TDD principles and dogfooding throughout the development enabled rapid iterations and
valuable community contributions, including Python support. The community’s warm reception,
enthusiastic feedback, and collaborative spirit have been profoundly motivating.&lt;/p&gt;
&lt;p&gt;I&#39;m especially grateful to my mentor &lt;a href=&quot;https://recurse.se/&quot;&gt;Martin&lt;/a&gt;, whose encouragement and belief
in the idea helped bring it to life.&lt;/p&gt;
&lt;p&gt;Feel free to explore &lt;a href=&quot;https://github.com/nizos/tdd-guard&quot;&gt;TDD Guard&lt;/a&gt;, and please reach out with
feedback or contributions. Your insights are invaluable and greatly appreciated.&lt;/p&gt;

    </content>
  </entry>
  <entry>
    <title>Agentic TDD</title>
    <link href="https://nizar.se/agentic-tdd/"/>
    <updated>2025-06-17T00:00:00Z</updated>
    <id>https://nizar.se/agentic-tdd/</id>
    <link rel="enclosure" type="image/jpeg" href="https://nizar.se/uploads/hand-tools.jpg" />
    <content type="html">
      &lt;img src="https://nizar.se/uploads/hand-tools.jpg" alt="Two crossed wrenches on a white surface, symbolizing development tools and craftsmanship" /&gt;
      &lt;p&gt;Since I started programming, I&#39;ve insisted on always writing my own code. It wasn&#39;t out of
necessity; it was a personal choice. Even as LLMs (Large Language Models) became part of my
workflow, I stayed firm about handling production code myself. Last week, that changed.&lt;/p&gt;
&lt;h2&gt;Exploring Coding Agents&lt;/h2&gt;
&lt;p&gt;After seeing countless demos online and reading about new workflows, I decided it was time to
experience an AI-powered coding agent myself. I subscribed to Claude Code and jumped into a
FigJam-inspired whiteboard project. To my surprise, Claude Code handled almost everything: it
suggested dependencies, initialized the project, set up tools, configured GitHub CI and security
workflows, and even proposed a detailed project plan with tasks.&lt;/p&gt;
&lt;p&gt;It&#39;s one thing to watch demos; it&#39;s another to be on the receiving end of an agent that understands
your intentions. Experiencing it firsthand was genuinely surprising. There was something uniquely
special about how it interacted and adapted to my needs.&lt;/p&gt;
&lt;h2&gt;First Encounter with Agentic TDD&lt;/h2&gt;
&lt;p&gt;That sense of novelty really hit home when I guided Claude Code through Test-Driven Development
(TDD). At first, I needed to spell out the process clearly in its instructions. But once the
guidelines were set, watching it autonomously follow TDD principles was unexpectedly profound. It
reminded me of hearing the
&lt;a href=&quot;https://en.wikipedia.org/wiki/Daisy_Bell&quot;&gt;first song sung by a computer&lt;/a&gt;: unexpected, imperfect,
but a glimpse of something bigger.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://nizar.se/uploads/claude-code-tdd.gif&quot; alt=&quot;Demo of Claude Code doing TDD&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;p&gt;To help Claude Code stay on track, I provided it with a pre-commit script that handled formatting,
linting, and running both unit and integration tests. This made the agent&#39;s workflow more consistent
and reduced the need for explicit guidance.&lt;/p&gt;
&lt;h2&gt;Where the Agent Falls Short&lt;/h2&gt;
&lt;p&gt;The initial excitement, however, was quickly tempered by reality. It didn&#39;t take long to see why
software engineers remain essential. I was still responsible for critical architectural decisions
and testing strategies, which is especially tricky when working with canvas-rendered elements that
can&#39;t be easily tested with standard DOM queries. I often found myself balancing simplicity and
complexity.&lt;/p&gt;
&lt;p&gt;Sometimes, Claude Code defaulted to &amp;quot;safe&amp;quot; behaviors: adding new functions instead of refactoring
existing ones (likely to avoid breaking working code), or skipping refactoring in test code unless
prompted. Personally, I prefer tests to remain clean and concise—a discipline I picked up from
senior colleagues at &lt;a href=&quot;https://factor10.com/&quot;&gt;factor10&lt;/a&gt;. Extracting common setup logic into helpers
keeps tests readable and maintainable.&lt;/p&gt;
&lt;p&gt;Other times, the agent&#39;s shortcuts forced me to intervene. For example, Claude Code disabled a
linting rule instead of correcting a typing issue. It also tried to revert a package upgrade because
the new version required configuration changes. In both cases, I had to step in, clarify my
preferences, and update its guidelines.&lt;/p&gt;
&lt;h2&gt;Putting it to Work in Production&lt;/h2&gt;
&lt;p&gt;Wanting to see how it performed in the real world, I started using Claude Code in a client project
where we&#39;re evaluating AI tools for developer productivity. In these larger, practical scenarios, it
performed better than I expected. With some deliberate guidance, it proved invaluable for rapid
prototyping and managing huge amounts of information. I still found myself &amp;quot;babysitting&amp;quot; a bit:
refining test helpers, nudging it towards architectural simplifications, and occasionally pulling it
back on track. Still, the early results were genuinely encouraging, both for the client and the
team.&lt;/p&gt;
&lt;p&gt;What stood out wasn&#39;t just the speed from idea to prototype, but how the agent made discovery and
iteration less tedious. Tracing logic across dozens of files, validating assumptions, and testing
multiple hypotheses all became much faster. While the agent&#39;s code wasn&#39;t always production-ready,
having something concrete to refine often surfaced improvements and insights that only became
apparent once I could interact with a real implementation.&lt;/p&gt;
&lt;h2&gt;Productivity Gains &amp;amp; Their Costs&lt;/h2&gt;
&lt;p&gt;This productivity boost raised some interesting tradeoffs. I could spend the saved time on
quality—optimizing performance, refining tooling, or enhancing user experience—while keeping up the
same pace. Or, I could use the boost to simply get more done, faster. Right now, I&#39;m balancing both
increased speed and quality.&lt;/p&gt;
&lt;p&gt;It&#39;s not that the agent produces better code than I could have, or solves problems I couldn&#39;t. The
real value is how quickly I can move through possibilities, validate approaches, and focus my
attention where it matters. Sometimes it suggests alternatives I hadn&#39;t considered, but the biggest
gain is simply more time and space to refine and improve ideas.&lt;/p&gt;
&lt;p&gt;But as more work got done in less time, bottlenecks shifted elsewhere. Code reviews, in particular,
became a new pinch point. Personally, I&#39;m not a big fan of traditional pull request workflows; the
important design decisions should ideally happen upfront through pair programming or quick
collaborative discussions. Real-time collaborations clarify intentions and issues before they
snowball.&lt;/p&gt;
&lt;p&gt;Test and pipeline performance can quickly become a bottleneck. With TDD, tests are run multiple
times for every change, and this overhead grows even more noticeable when working agentically. If
your test suites or pipelines aren&#39;t well-optimized, you&#39;ll quickly feel the drag.&lt;/p&gt;
&lt;h2&gt;Why Agentic TDD&lt;/h2&gt;
&lt;p&gt;Maybe agentic TDD isn&#39;t for everyone, and that&#39;s fine. Personally, TDD keeps me productive,
effective, and sane. It might slow down the agent, but it also ensures I understand, agree with, and
can trace the changes being made. The reasoning and the tests the agent creates give me context I
need to follow along or step in when something feels off.&lt;/p&gt;
&lt;p&gt;I also wonder if TDD could reduce the risk of introducing &amp;quot;protected&amp;quot; or memorized code, though I
can&#39;t say for certain. Either way, it&#39;s an intriguing thought.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Looking back, I&#39;m struck by how quickly agentic coding became mainstream. It happened almost
overnight. Not long ago, making the most of LLMs meant we had to manage the plan ourselves: track
tasks in our heads, handling each step manually, and guiding the model by reviewing outputs and
feeding back the results. We were the bridge between the model and the tools, stitching everything
together one prompt at a time.&lt;/p&gt;
&lt;p&gt;Now, that same &lt;a href=&quot;https://philz.dev/blog/agent-loop/&quot;&gt;loop runs inside the agent&lt;/a&gt;. Instead of holding
the task list in mind and steering each operation, we hand over the process. It&#39;s remarkable how
such a small shift in workflow—passing off this mental orchestration—has had such an outsized
impact.&lt;/p&gt;
&lt;p&gt;Similarly, the
&lt;a href=&quot;https://www.anthropic.com/news/agent-capabilities-api&quot;&gt;MCP (Model Context Protocol) loop&lt;/a&gt; is both
simple yet impactful. Claude Code retrieves available tools, reasons about appropriate actions,
executes tool calls, and iterates until successful.&lt;/p&gt;
&lt;p&gt;There are still times I want to just make changes myself, and I&#39;m figuring out ways to minimize
those interruptions. Of course, some limitations are tough to work around. For example, when Claude
Code tries to rename things across files with &lt;code&gt;grep&lt;/code&gt; or &lt;code&gt;regex&lt;/code&gt; and stumbles on syntax variations.&lt;/p&gt;
&lt;p&gt;Even so, Claude Code hasn&#39;t just made me fast—it&#39;s changed how I think about building software. The
real shift is realizing that good results and confidence in my work don&#39;t depend on typing every
line myself. I still review and shape the code, but I can now focus my effort where it matters the
most: iterating more quickly, exploring new options, and making higher-impact decisions.&lt;/p&gt;
&lt;p&gt;I&#39;m still learning to collaborate with it, and I&#39;m curious to see where this journey goes next. But
I already know one thing: I don&#39;t want to go back.&lt;/p&gt;
&lt;h2&gt;Practical Tips&lt;/h2&gt;
&lt;p&gt;If you&#39;re curious about Claude Code or are already experimenting, here are personal tips:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Interrupt early if the agent veers off track.&lt;/li&gt;
&lt;li&gt;Commit frequently. You can also ask it to undo changes.&lt;/li&gt;
&lt;li&gt;Compact context between large tasks for best results.&lt;/li&gt;
&lt;li&gt;Regularly refine instructions, something I admittedly don&#39;t always prioritize enough.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Things to try:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use &lt;a href=&quot;https://github.com/punkpeye/awesome-mcp-servers&quot;&gt;MCP servers&lt;/a&gt; to provide the agent with
direct feedback.&lt;/li&gt;
&lt;li&gt;Try the planning mode for investigative tasks.&lt;/li&gt;
&lt;li&gt;Share screenshots to clarify complex tasks.&lt;/li&gt;
&lt;li&gt;Leverage tools like
&lt;a href=&quot;https://docs.anthropic.com/en/docs/build-with-claude/prompt-engineering/prompt-improver&quot;&gt;Prompt Improver&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;For advanced users: experiment with the
&lt;a href=&quot;https://github.com/anthropics/claude-code/issues/1052&quot;&gt;git worktree pattern&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you try agentic TDD, be sure to give the agent clear, explicit instructions to prevent shortcuts.
Otherwise, it might begin implementing as soon as any test fails, regardless of the reason, or pack
too many assertions into a single test. I found the following instructions helpful to include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Always start with a test that fails for the correct reason.&lt;/li&gt;
&lt;li&gt;Write only one test at a time.&lt;/li&gt;
&lt;li&gt;Use a single assertion per test.&lt;/li&gt;
&lt;li&gt;Verify test infrastructure before testing actual behavior.&lt;/li&gt;
&lt;li&gt;Provide stub implementations to avoid errors unrelated to actual behavior.&lt;/li&gt;
&lt;li&gt;Tests should fail due to incorrect behavior, not on missing methods/properties.&lt;/li&gt;
&lt;li&gt;Implement the minimal necessary code to pass the test.&lt;/li&gt;
&lt;li&gt;Don&#39;t add properties, methods, or logic that aren&#39;t required by the current failing test.&lt;/li&gt;
&lt;li&gt;Once the test passes, refactor both test and implementation code.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Lastly, check out the official
&lt;a href=&quot;https://www.anthropic.com/engineering/claude-code-best-practices&quot;&gt;Claude Code Best Practices&lt;/a&gt;
guide. It&#39;s genuinely helpful.&lt;/p&gt;

    </content>
  </entry>
  <entry>
    <title>How I Use LLMs as a Developer</title>
    <link href="https://nizar.se/how-i-use-llms-as-a-developer/"/>
    <updated>2025-04-25T00:00:00Z</updated>
    <id>https://nizar.se/how-i-use-llms-as-a-developer/</id>
    <link rel="enclosure" type="image/jpeg" href="https://nizar.se/uploads/llm-visualization-social-image.jpg" />
    <content type="html">
      &lt;img src="https://nizar.se/uploads/llm-visualization-social-image.jpg" alt="Visualization of a Large Language Model" /&gt;
      &lt;p&gt;I have been using Large Language Models (LLMs) for the last two years. During this time, I’ve
noticed that people’s opinions about LLMs vary dramatically. The community seems split—some
developers swear by them, while others remain skeptical or outright dismissive. Personally, I find
these differences fascinating because they highlight that there’s no single “right” way to think
about LLMs, and definitely not a single right way of using them. Instead, the value you get largely
depends on how you choose to approach them.&lt;/p&gt;
&lt;p&gt;Over the past year, I’ve had several conversations where people asked me how I actually use LLMs in
my day-to-day work. Rather than repeating myself, I decided to write it down. This post is a
reflection of my own journey–how my usage has evolved, what I’ve learned, and how LLMs have changed
the way I work as a developer.&lt;/p&gt;
&lt;h2&gt;Exploring and Experimenting&lt;/h2&gt;
&lt;p&gt;When I first started out, I was mainly curious about what these models could actually do. I tried
asking them to generate tests, code snippets, and documentation. It was impressive, but I quickly
encountered familiar pitfalls: hallucinations,
&lt;a href=&quot;https://www.marilynfrank.com/word/prompt-drift&quot;&gt;prompt drift&lt;/a&gt;, and context or output length
limitations. The rapid pace of model updates also introduced noticeable shifts–some users even
complained that the models felt “lazy” or less helpful after certain updates.&lt;/p&gt;
&lt;p&gt;Interestingly, I noticed that I consistently got better results when saying “please” and “thank
you”. At first, this seemed silly, but later studies confirmed that polite interactions genuinely
influence result quality. Eventually, I realized it wasn’t merely about emotional pleading–being
deliberate and precise in my communication made the real difference. Clearly stating goals,
providing explicit context, and sharing relevant examples consistently led to improved outcomes.&lt;/p&gt;
&lt;p&gt;Soon, my interactions became naturally conversational. I’d clearly describe an issue, provide tests
or code snippets, and outline exactly what I am aiming to achieve. If the model made incorrect
assumptions, I’d nudge it gently in the right direction. If its suggestions were suboptimal, I’d ask
clarifying questions. Over time, this approach felt less like prompting and more like a technical
discussion.&lt;/p&gt;
&lt;h2&gt;Dealing with Context Drift&lt;/h2&gt;
&lt;p&gt;As conversations lengthened, context drift became noticeable. The model would occasionally lose
track of details provided earlier. However, as someone who practices Test-Driven Development (TDD),
this wasn’t a major issue. Breaking problems into smaller increments naturally prevented context
overload. Between iterations, I’d briefly remind it of critical details or qualities I aimed for.&lt;/p&gt;
&lt;p&gt;While structured prompting greatly improved the results, it also made my prompts longer and more
cumbersome over time.&lt;/p&gt;
&lt;h2&gt;Becoming A Better Technical Communicator&lt;/h2&gt;
&lt;p&gt;With practice, I learned to ask clearer, more concise questions without needing lengthy examples or
constant repetition of context. It pushed me to become more precise when articulating technical
challenges, patterns, and specifications–ultimately sharpening my technical communication overall.&lt;/p&gt;
&lt;p&gt;For example, instead of pasting a block of code and asking: “I have this code that maps over
observables and applies some logic, but it doesn’t seem to emit anything in some cases. Any idea
what might be wrong?”&lt;/p&gt;
&lt;p&gt;I might now ask something like: “I’m working on a data transformation pipeline that filters and maps
over nested observables. Under certain conditions, the inner stream completes before emitting. What
are some clean strategies to avoid silent drops in that case?”&lt;/p&gt;
&lt;p&gt;Or if I’m exploring alternatives to a design: “How could we generalize this pattern so it supports
multiple input types while keeping the transformation logic decoupled from the source format?”&lt;/p&gt;
&lt;p&gt;Being able to formulate questions like these, without dragging in unrelated implementation details,
has helped me communicate more effectively overall.&lt;/p&gt;
&lt;h2&gt;Why I Still Write My Own Code&lt;/h2&gt;
&lt;p&gt;An important principle I’ve always adhered to is never copy-pasting code written by others into my
projects. Naturally, this extended to code generated by LLMs. Many developers happily embrace direct
code generation, and perhaps someday I’ll reconsider, but right now, it just doesn’t feel right to
me. Maybe it’s philosophical, but I firmly believe the code I introduce should be code that I have
personally written.&lt;/p&gt;
&lt;p&gt;This principle has shaped my relationships with LLMs significantly. Rather than using them for code
completion or direct generation, I treat them as conversational partners–tools for discovery,
prototyping, rubber-ducking, and exploring curiosities. My interactions typically begin when I sense
potential improvements or approaches I haven’t yet considered. I ask questions, explore
possibilities, and deepen my understanding. Only once I clearly see the solution, and fully grasp it
myself, do I write the actual code.&lt;/p&gt;
&lt;h2&gt;Do LLMs make us Smarter or Lazier?&lt;/h2&gt;
&lt;p&gt;This approach brings up the classic question: Does using calculators, search engines, or LLMs make
us smarter or lazier? Personally, I think it depends entirely on the mindset. Imagine working
alongside smarter, more experienced colleagues–do you delegate the difficult tasks to them, or do
you actively learn from their expertise? That’s how I view my relationship with LLMs: an opportunity
to question, learn, and become a better developer.&lt;/p&gt;
&lt;h2&gt;What’s Next on My Journey?&lt;/h2&gt;
&lt;p&gt;The pace of innovation around LLMs continues to astonish me. I’m particularly eager to explore
several emerging tools and practices:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Multi-Document Context &lt;br /&gt;
Allows models to pull in relevant information from multiple sources, helping them reason more
effectively across large or fragmented codebases and documents. Instead of giving all the context
upfront, you define reusable instructions or rules, and the model knows where to look and what to
apply. (&lt;a href=&quot;https://github.com/benallfree/awesome-mdc/blob/main/what-is-mdc.md&quot;&gt;awesome-mdc&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Task Management System &lt;br /&gt;
These help break complex projects into smaller, manageable tasks and orchestrate their execution
effectively. (&lt;a href=&quot;https://github.com/eyaltoledano/claude-task-master&quot;&gt;Claude Task Master&lt;/a&gt;,
&lt;a href=&quot;https://docs.roocode.com/features/boomerang-tasks&quot;&gt;Boomerang Tasks&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Model Context Protocol &lt;br /&gt;
A protocol that lets models seamlessly integrate with various tools and data sources,
dramatically expanding their capabilities.
(&lt;a href=&quot;https://modelcontextprotocol.io/introduction&quot;&gt;MCP Introduction&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Browser Automation for AI &lt;br /&gt;
Makes websites directly accessible to AI agents, greatly expanding how models can interact with
web applications. (&lt;a href=&quot;https://docs.browser-use.com/introduction&quot;&gt;Browser Use&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;AI Integration with GitHub Actions &lt;br /&gt;
Integrating AI models directly into development workflows, enriching and automating parts of the
CI/CD process.
(&lt;a href=&quot;https://docs.github.com/en/github-models/integrating-ai-models-into-your-development-workflow#using-ai-models-with-github-actions&quot;&gt;GitHub Actions&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Admittedly, adopting some of these new technologies might challenge my current principle of writing
all the code myself. Nevertheless, I’m eagerly looking forward to seeing where this journey takes me
next.&lt;/p&gt;

    </content>
  </entry>
  <entry>
    <title>Implementing Durable Entities in Kotlin - Final Enhancements</title>
    <link href="https://nizar.se/implementing-durable-entities-in-kotlin-final-enhancements/"/>
    <updated>2025-01-07T00:00:00Z</updated>
    <id>https://nizar.se/implementing-durable-entities-in-kotlin-final-enhancements/</id>
    <link rel="enclosure" type="image/jpeg" href="https://nizar.se/uploads/chess.jpg" />
    <content type="html">
      &lt;img src="https://nizar.se/uploads/chess.jpg" alt="Black and white chess pieces on a blurred background." /&gt;
      &lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Throughout this series, we&#39;ve explored Durable Entities from the ground up: managing state, creating
entities, signaling, cross-communication, and two-way interactions. There steps have culminated in a
flexible and functional system for handling stateful workflows in Kotlin.&lt;/p&gt;
&lt;p&gt;In this final post, we&#39;ll refine and enhance our implementation. By introducing abstractions and a
DSL-like syntax, we&#39;ll improve readability, and aligns it with the native experience. This
consolidation will prepare our implementation for real-world usage and future expansions.&lt;/p&gt;
&lt;h2&gt;Enhancing Durable Entities with Abstractions&lt;/h2&gt;
&lt;h3&gt;Creating the DurableEntityContext Class&lt;/h3&gt;
&lt;p&gt;We encapsulate common entity operations into a reusable &lt;code&gt;DurableEntityContext&lt;/code&gt; class. This
abstraction simplifies the implementation of entity logic:&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;DurableEntityContext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; ctx&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; TaskOrchestrationContext&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; currentOperation&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Operation&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;waitForOperation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Operation &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        currentOperation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;waitForExternalEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;EntityOperation&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; String&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;java&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; objectMapper&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;readValue&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Operation&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;it&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; currentOperation&lt;br /&gt;            &lt;span class=&quot;token operator&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;IllegalStateException&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Operation could not been initialized.&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;inline&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;reified&lt;/span&gt; T&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; T &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getEntityState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;instanceId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; T&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;java&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token operator&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;IllegalStateException&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Entity state has not been initialized.&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;newState&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Any&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setCustomStatus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;newState&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;inline&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;reified&lt;/span&gt; T &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Any&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getInput&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; T &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; T&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;cast&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;currentOperation&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;input&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;T&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;returnResult&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;value&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; T&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; operation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            currentOperation&lt;br /&gt;                &lt;span class=&quot;token operator&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;IllegalStateException&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;No operation in progress to return result for&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;requesterId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; responseEventName&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            operation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;requesterId &lt;span class=&quot;token keyword&quot;&gt;to&lt;/span&gt; operation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;responseEventName&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;requesterId &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; responseEventName &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; resultOperation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Operation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Result&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; input &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; signalInput &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token function&quot;&gt;SignalEntityInput&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;                    entityId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; requesterId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                    operation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; resultOperation&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                    eventName &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; responseEventName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;            ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;signalEntity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;signalInput&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;IllegalArgumentException&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Requester ID or response event name not provided&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Retrieving Entity State with Activities&lt;/h2&gt;
&lt;h3&gt;Creating the getEntityState Function&lt;/h3&gt;
&lt;p&gt;We define a helper function for retrieving the state of an entity using an activity:&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;T&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; TaskOrchestrationContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getEntityState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    entityId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    returnType&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Class&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;T&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Task&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;T&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;callActivity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;GetEntityState&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token function&quot;&gt;GetEntityStateInput&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entityId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        returnType&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@FunctionName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;GetEntityState&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getEntityStateActivity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token annotation builtin&quot;&gt;@DurableActivityTrigger&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;input&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; input&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; GetEntityStateInput&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token annotation builtin&quot;&gt;@DurableClientInput&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;durableContext&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; durableContext&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; DurableClientContext&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Int&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; durableContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;client&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getInstanceMetadata&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;input&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;entityId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;readCustomStatusAs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Int&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;java&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Refactoring the Counter Entity&lt;/h2&gt;
&lt;h3&gt;Updating the Counter Logic&lt;/h3&gt;
&lt;p&gt;With the &lt;code&gt;DurableEntityContext&lt;/code&gt; abstraction, the &lt;code&gt;Counter&lt;/code&gt; entity is simplified:&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@FunctionName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Counter&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token annotation builtin&quot;&gt;@DurableOrchestrationTrigger&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;taskCtx&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; taskCtx&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; TaskOrchestrationContext&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; ctx &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;DurableEntityContext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;taskCtx&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;waitForOperation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;currentOperation&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;lowercase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;add&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;getState&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Int&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;getInput&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Int&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;reset&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;get&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;returnResult&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;getState&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Int&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Adding State Rehydration&lt;/h2&gt;
&lt;h3&gt;Initializing State&lt;/h3&gt;
&lt;p&gt;To ensure the entity state is properly initialized, we define an &lt;code&gt;initializeState&lt;/code&gt; function:&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;initializeState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;initialValue&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Any&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; state &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getEntityState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;instanceId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Any&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;java&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;state &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setCustomStatus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;initialValue&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Introducing a DSL-like Syntax&lt;/h2&gt;
&lt;h3&gt;Simplifying the Entity Loop&lt;/h3&gt;
&lt;p&gt;We encapsulate the entity loop in the &lt;code&gt;DurableEntityContext&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;runEntityLoop&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;handleOperation&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; DurableEntityContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; Unit&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token function&quot;&gt;waitForOperation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;handleOperation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Abstracting the Entity Function&lt;/h3&gt;
&lt;p&gt;We introduce an &lt;code&gt;asEntity&lt;/code&gt; function to further streamline entity definitions:&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;asEntity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    taskCtx&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; TaskOrchestrationContext&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    initialState&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Any&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    block&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; DurableEntityContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; Unit&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; ctx &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;DurableEntityContext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;taskCtx&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;initializeState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;initialState&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;runEntityLoop&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Final Entity Implementation&lt;/h3&gt;
&lt;p&gt;The Counter entity now has a clean and expressive syntax:&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@FunctionName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Counter&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@DurableOrchestrationTrigger&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ctx&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; ctx&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; TaskOrchestrationContext&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;asEntity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; initialState &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;currentOperation&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;lowercase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;add&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;getState&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Int&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; getInput&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Int&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;reset&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;get&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;returnResult&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;getState&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Int&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;With this final post, we have refined our Durable Entities implementation, making it cleaner, more
expressive, and better suited for real-world usage. By introducing abstractions like
DurableEntityContext, we reduced boilerplate and improved maintainability. We also added state
rehydration and entity state retrieval via activities, ensuring consistency and reliability.
Finally, a DSL-like syntax makes entity definitions more intuitive and streamlined.&lt;/p&gt;
&lt;p&gt;This concludes our series, having covered all fundamental functionalities. The implementation
provides a solid foundation and can be further optimized for performance.&lt;/p&gt;
&lt;h2&gt;Read More&lt;/h2&gt;
&lt;p&gt;This post is part of the
&lt;a href=&quot;https://nizar.se/implementing-durable-entities-in-kotlin&quot;&gt;Implementing Durable Entities in Kotlin&lt;/a&gt; series.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Previous&lt;/strong&gt;: &lt;a href=&quot;https://nizar.se/implementing-durable-entities-in-kotlin-calling-entities&quot;&gt;Calling Entities&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

    </content>
  </entry>
  <entry>
    <title>Implementing Durable Entities in Kotlin - Calling Entities</title>
    <link href="https://nizar.se/implementing-durable-entities-in-kotlin-calling-entities/"/>
    <updated>2025-01-06T00:00:00Z</updated>
    <id>https://nizar.se/implementing-durable-entities-in-kotlin-calling-entities/</id>
    <link rel="enclosure" type="image/jpeg" href="https://nizar.se/uploads/chess.jpg" />
    <content type="html">
      &lt;img src="https://nizar.se/uploads/chess.jpg" alt="Black and white chess pieces on a blurred background." /&gt;
      &lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;So far, we have built a solid foundation for Durable Entities in Kotlin. We have established
stateful entities that persist data and allowed them to interact dynamically through signaling. We
have also introduced cross-entity communication, where entities can notify each other of significant
events.&lt;/p&gt;
&lt;p&gt;However, all interactions so far have been fire-and-forget. Entities can send signals, but they
don&#39;t receive immediate responses. This approach is sufficient for many scenarios, but real-world
applications often require two-way communication.&lt;/p&gt;
&lt;p&gt;In this post, we introduce entity calling, which allows entities to invoke operations and receive
responses. This unlocks more advanced workflows, such as querying state, making decisions based on
results, and chaining interactions in a more structured way.&lt;/p&gt;
&lt;p&gt;To demonstrate this, we enhance our &lt;code&gt;Counter&lt;/code&gt; entity to support calls, allowing clients and
orchestrations to retrieve its current value. Along the way, we&#39;ll introduce best practices for
handling entity calls safely with Durable Functions constraints.&lt;/p&gt;
&lt;h2&gt;Constraints in Durable Orchestrations&lt;/h2&gt;
&lt;p&gt;In a previous post where we introduced state persistence, we demonstrated how we can query the state
of an entity using the custom status metadata. However, as we have previously seen, orchestrations
replay their executions to ensure reliability. Any non-deterministic operation, such as fetching a
new timestamp or making an external API request, could lead to inconsistent results. Because of
this, entity calls need a structured, replay-safe mechanism to avoid breaking the orchestration
model.&lt;/p&gt;
&lt;p&gt;Instead of calling entities directly, we establish a request-response patterns where the caller
requests an operation from an entity, the entity processes the request and sends a response, and the
caller waits for and retrieves the response.&lt;/p&gt;
&lt;p&gt;Another challenge is ensuring that responses are mapped to their corresponding requests. Since each
entity call runs within an orchestrator that may replay multiple times, using a traditional random
ID to track calls would introduce non-determinism. Instead, we need a deterministic way to generate
unique event names to safely map responses to their originating requests.&lt;/p&gt;
&lt;h2&gt;Building a Request-Response Pattern for Entity Calls&lt;/h2&gt;
&lt;h3&gt;Extending the Data Model&lt;/h3&gt;
&lt;p&gt;To support entity calls, we extend our data classes. Instead of just sending operation names and
input values, we now include metadata for responses.&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Operation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; input&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Any&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; requesterId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; responseEventName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;SignalEntityInput&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; entityId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; operation&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Operation&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; eventName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;requesterId&lt;/code&gt; field identifies who made the request, while &lt;code&gt;responseEventName&lt;/code&gt; specifies the
name of the event to which the response should be sent. The &lt;code&gt;eventName&lt;/code&gt; in the &lt;code&gt;SignalEntityInput&lt;/code&gt;
ensures the result is mapped correctly to its corresponding request.&lt;/p&gt;
&lt;h2&gt;Implementing the Call Logic&lt;/h2&gt;
&lt;p&gt;With our extended data model in place, we define a &lt;code&gt;callEntity&lt;/code&gt; function that facilitates
request-response interactions between orchestrators and entities. Unlike fire-and-forget signals,
this function ensures that an orchestrator can invoke an operation and reliably retrieve a response.&lt;/p&gt;
&lt;p&gt;To achieve this, we introduce a structured event-based mechanism that maintains determinism and
orchestration safety. When an orchestrator calls an entity, it generates a deterministically unique
event name to track its corresponding response. The orchestrator then waits for an external event to
receive the result before continuing execution.&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;T&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; TaskOrchestrationContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;callEntity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    entityId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    operationName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    operationInput&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Any&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    returnType&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Class&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;T&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; T &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Generate a deterministically safe and unique response event name&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; responseEventName &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ResponseEvent_&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;newUUID&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Set up the listener for the response event&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; resultTask &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;waitForExternalEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;responseEventName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; String&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;java&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Generate the payload&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; operation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token function&quot;&gt;Operation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;            name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; operationName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            input &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; operationInput&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            requesterId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;instanceId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            responseEventName &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; responseEventName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; input &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;SignalEntityInput&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entityId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; entityId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; operation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; operation&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Emit the signal to the entity&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;signalEntity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;input&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Wait for the response event&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; resultJson &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; resultTask&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Parse operation input into requested return type and return it&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; resultOperation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; objectMapper&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;readValue&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Operation&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;resultJson&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; objectMapper&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;convertValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;resultOperation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;input&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; returnType&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To maintain determinism, we generate a unique response event name using &lt;code&gt;newUUID()&lt;/code&gt;, which is safe
for orchestration replays as it remains consistent. Using a non-deterministic value like
&lt;code&gt;UUID.randomUUID()&lt;/code&gt; would break replay behavior, making it unsuitable for Durable Functions.&lt;/p&gt;
&lt;p&gt;Once the event name is generated, we register an event listener using &lt;code&gt;waitForExternalEvent&lt;/code&gt;. We
then package the request into &lt;code&gt;SignalEntityInput&lt;/code&gt; and send it to the entity. The entity processes
the request and emits a response event back to the orchestrator using the stored
&lt;code&gt;responseEventName&lt;/code&gt;. WHen the orchestrator receives the response, it deserializes the result and
returns it as the expected data type.&lt;/p&gt;
&lt;h3&gt;Enhancing Signal Logic&lt;/h3&gt;
&lt;p&gt;To facilitate structured entity communication, we enhance our signaling logic by introducing an
activity function that serves as an intermediary. The &lt;code&gt;signalEntity&lt;/code&gt; function is now responsible for
routing signals safely while ensuring Durable Functions constraints are followed.&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; TaskOrchestrationContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;signalEntity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;input&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; SignalEntityInput&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;callActivity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;SignalEntity&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; input&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@FunctionName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;SignalEntity&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;signalEntityActivity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token annotation builtin&quot;&gt;@DurableActivityTrigger&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;input&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; input&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; SignalEntityInput&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token annotation builtin&quot;&gt;@DurableClientInput&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ctx&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; ctx&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; DurableClientContext&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;signalEntity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;input&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; DurableTaskClient&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;signalEntity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;input&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; SignalEntityInput&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; operationJSON &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; objectMapper&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;writeValueAsString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;input&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;operation&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; eventName &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; input&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;eventName &lt;span class=&quot;token operator&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;EntityOperation&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;raiseEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;input&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;entityId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; eventName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; operationJSON&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By routing signals through an activity function, we ensure that Durable Task Client from within an
orchestrator. Additionally, the &lt;code&gt;eventName&lt;/code&gt; parameter ensures that responses are mapped correctly to
their corresponding requests.&lt;/p&gt;
&lt;h3&gt;Adding Support for Entity Calls&lt;/h3&gt;
&lt;p&gt;With a safe signaling mechanism in place, we modify our counter to support calls rather than just
fire-and-forget signals. Specifically, we introduce a &lt;code&gt;Get&lt;/code&gt; operation that returns the current
counter value to the requester.&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@FunctionName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Counter&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@DurableOrchestrationTrigger&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ctx&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; ctx&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; TaskOrchestrationContext&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; counter &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;    ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setCustomStatus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;counter&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; operation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;waitForEntityOperation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;operation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Add&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; counter &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;operation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;input &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; Int&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Get&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;                    operation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;requesterId &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; operation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;responseEventName &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; resultOperation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Operation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Result&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; input &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; counter&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; signalInput &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;                        &lt;span class=&quot;token function&quot;&gt;SignalEntityInput&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;                            entityId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; operation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;requesterId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                            operation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; resultOperation&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                            eventName &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; operation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;responseEventName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;                    ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;signalEntity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;signalInput&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Reset&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; counter &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setCustomStatus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;counter&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Instead of immediately returning the value, the counter packages the result as an operation and
sends it to the requester. The &lt;code&gt;requesterId&lt;/code&gt; and &lt;code&gt;responseEventName&lt;/code&gt; ensure that the response is
delivered to the correct waiting orchestrator.&lt;/p&gt;
&lt;h3&gt;Abstracting the Result Logic&lt;/h3&gt;
&lt;p&gt;We encapsulate the logic for returning results into an extension function:&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;T&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; TaskOrchestrationContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;returnResult&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;operation&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Operation&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; T&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;operation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;requesterId &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; operation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;responseEventName &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; resultOperation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Operation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Result&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; input &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; signalInput &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token function&quot;&gt;SignalEntityInput&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;                entityId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; operation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;requesterId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                operation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; resultOperation&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                eventName &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; operation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;responseEventName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;signalEntity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;signalInput&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;IllegalArgumentException&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Requester ID or response event name not provided&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this, we simplify the &lt;code&gt;Counter&lt;/code&gt; entity further:&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@FunctionName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Counter&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@DurableOrchestrationTrigger&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ctx&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; ctx&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; TaskOrchestrationContext&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; counter &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;    ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setCustomStatus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;counter&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; operation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;waitForEntityOperation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;operation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Add&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; counter &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;operation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;input &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; Int&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Get&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;returnResult&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;operation&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; counter&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Reset&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; counter &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setCustomStatus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;counter&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Testing Entity Calls&lt;/h2&gt;
&lt;h3&gt;Creating a CounterCaller Orchestration&lt;/h3&gt;
&lt;p&gt;We define a &lt;code&gt;CounterCaller&lt;/code&gt; orchestration to test the &lt;code&gt;callEntity&lt;/code&gt; function:&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@FunctionName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;CounterCaller&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;counterCaller&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token annotation builtin&quot;&gt;@DurableOrchestrationTrigger&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ctx&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; ctx&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; TaskOrchestrationContext&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    context&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ExecutionContext&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Get the ID of the Counter from the input&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; counterId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getInput&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;String&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;java&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// For demo: Yield control to ensure the runtime registers everything first&lt;/span&gt;&lt;br /&gt;    ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createTimer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Duration&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ofSeconds&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Call the Get operation on the Counter&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; counterValue &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;callEntity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;            entityId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; counterEntityId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            operationName &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Get&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            returnType &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Int&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;java&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Log the returned counter value&lt;/span&gt;&lt;br /&gt;    context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;logger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Received &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;counterValue&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Defining the Orchestration HTTP Trigger&lt;/h3&gt;
&lt;p&gt;We create an HTTP trigger to initialize both the &lt;code&gt;Counter&lt;/code&gt; and &lt;code&gt;CounterCaller&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@FunctionName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;CreateCounterOrchestration&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createCounterOrchestration&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token annotation builtin&quot;&gt;@HttpTrigger&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;        name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;req&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        methods &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;HttpMethod&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;GET&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        authLevel &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; AuthorizationLevel&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ANONYMOUS&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    request&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; HttpRequestMessage&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Optional&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;String&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token annotation builtin&quot;&gt;@DurableClientInput&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ctx&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; ctx&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; DurableClientContext&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; HttpResponseMessage &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Create a Counter and a CounterCaller&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; counterId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Entity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;client&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Counter&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; callerId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Entity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;client&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;CounterCaller&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; counterId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Return an HTTP response containing the IDs&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; responseBody &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token string-literal multiline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&quot;&lt;br /&gt;        Created Counter and CounterCaller.&lt;br /&gt;        Counter ID: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;counterId&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&lt;br /&gt;        Caller ID: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;callerId&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&lt;br /&gt;    &quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;trimIndent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;success&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;responseBody&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Validating the Output&lt;/h3&gt;
&lt;p&gt;We run the setup and check the logs for the retrieved counter value:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;❯ &lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; https://durable-app.azurewebsites.net/api/CreateCounterOrchestration&lt;br /&gt;Created Counter and CounterCaller.&lt;br /&gt;Counter ID: 3feb953a-0f90-4aaa-81fa-13a96c3c9a6b&lt;br /&gt;Caller ID: 7005eee2-b644-4f71-9ec7-b7d18b09bc55&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-txt&quot;&gt;&lt;code class=&quot;language-txt&quot;&gt;2024-11-13T07:17:18Z   [Information]   CounterCaller: Started&lt;br /&gt;2024-11-13T07:17:18Z   [Information]   CounterCaller: received 0&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;What&#39;s Next?&lt;/h2&gt;
&lt;p&gt;With this we have developed the functionalities that we need to use Durable Entities in Kotlin. In
the next and final post in the series, we will refine our implementation by introducing abstractions
to simplify interactions and align our approach with the native Durable Entities experience.&lt;/p&gt;
&lt;h2&gt;Read Further&lt;/h2&gt;
&lt;p&gt;This post is part of the
&lt;a href=&quot;https://nizar.se/implementing-durable-entities-in-kotlin&quot;&gt;Implementing Durable Entities in Kotlin&lt;/a&gt; series.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Previous&lt;/strong&gt;: &lt;a href=&quot;https://nizar.se/implementing-durable-entities-in-kotlin-cross-communication&quot;&gt;Cross-Communication&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Next&lt;/strong&gt;: &lt;a href=&quot;https://nizar.se/implementing-durable-entities-in-kotlin-final-enhancements/&quot;&gt;Final Enhancements&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

    </content>
  </entry>
  <entry>
    <title>Implementing Durable Entities in Kotlin - Cross Communication</title>
    <link href="https://nizar.se/implementing-durable-entities-in-kotlin-cross-communication/"/>
    <updated>2025-01-05T00:00:00Z</updated>
    <id>https://nizar.se/implementing-durable-entities-in-kotlin-cross-communication/</id>
    <link rel="enclosure" type="image/jpeg" href="https://nizar.se/uploads/chess.jpg" />
    <content type="html">
      &lt;img src="https://nizar.se/uploads/chess.jpg" alt="Black and white chess pieces on a blurred background." /&gt;
      &lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;So far, we have built stateful entities that persist data and respond dynamically to external input
through signaling. However, all interactions have been one-directional: clients send commands, but
entities remain isolated from each other.&lt;/p&gt;
&lt;p&gt;Real-world applications often require entities to collaborate, exchanging updates and triggering
actions across a distributed system. This post introduces cross-entity communication, where entities
can signal each other and work together toward a shared goal.&lt;/p&gt;
&lt;p&gt;To demonstrate this, we introduce a monitor entity that listens for updates from the counter entity
whenever it reaches specific milestones.&lt;/p&gt;
&lt;h2&gt;Why Can&#39;t We Signal Entities Directly?&lt;/h2&gt;
&lt;p&gt;Signaling an entity from another entity or orchestrator using &lt;code&gt;DurableTaskClient&lt;/code&gt; might seem
straightforward, but it introduces reliability issues. Orchestrators replay executions for fault
tolerance and scalability. If they interact directly with external clients, they risk sending
duplicate signals, leading to unintended side effects.&lt;/p&gt;
&lt;p&gt;This constraint is fundamental to Durable Functions, ensuring consistency in distributed workflows,
as detailed in the
&lt;a href=&quot;https://learn.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-code-constraints?tabs=csharp#bindings&quot;&gt;Durable Entities constraints documentation&lt;/a&gt;.
Instead of allowing direct signaling, we introduce an activity function to handle communication.
Activities do not replay, ensuring that each signal is sent exactly once while maintaining
orchestration integrity.&lt;/p&gt;
&lt;h2&gt;Enabling Cross-Entity Communication&lt;/h2&gt;
&lt;p&gt;To ensure structured and reliable entity signaling, we introduce a signaling model that standardizes
communication between entities.&lt;/p&gt;
&lt;h3&gt;Defining a Structured Signaling Model&lt;/h3&gt;
&lt;p&gt;Instead of sending raw data, we define a structured format for consistent and predictable
inter-entity communication. The &lt;code&gt;Operation&lt;/code&gt; class remains unchanged and represents an action an
entity should take, optionally carrying input data. The &lt;code&gt;SignalEntityInput&lt;/code&gt; class bundles the target
entity ID with the operation, making signaling clearer and reusable.&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Operation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; input&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Any&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;SignalEntityInput&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; entityId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; operation&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Operation&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By encapsulating signaling details, this model simplifies passing information to the activity
function.&lt;/p&gt;
&lt;h2&gt;Handling Signals with an Activity Function&lt;/h2&gt;
&lt;p&gt;With a structured model in place, we define an activity function to safely handle signaling. Unlike
orchestrations, activities do not replay, making them the correct place to interact with
&lt;code&gt;DurableTaskClient&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@FunctionName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;SignalEntity&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;signalEntityActivity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token annotation builtin&quot;&gt;@DurableActivityTrigger&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;input&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; input&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; SignalEntityInput&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token annotation builtin&quot;&gt;@DurableClientInput&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;durableContext&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; durableContext&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; DurableClientContext&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    durableContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;signalEntity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;        input&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;entityId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        input&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;operation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        input&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;operation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;input&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The activity takes a &lt;code&gt;SignalEntityInput&lt;/code&gt; and sends a signal on behalf of the caller. Since
activities execute only once, they prevent duplicate signals, ensuring reliable inter-entity
communication.&lt;/p&gt;
&lt;h2&gt;Updating the Counter to Signal the Monitor&lt;/h2&gt;
&lt;p&gt;Now that we have a safe signaling mechanism, we modify the &lt;code&gt;Counter&lt;/code&gt; entity to notify the &lt;code&gt;Monitor&lt;/code&gt;
when reaching specific milestones. The counter initializes its state, listens for operations, and
updates its value accordingly. Whenever it reaches a multiple of 10, it signals the monitor.&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@FunctionName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Counter&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@DurableOrchestrationTrigger&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ctx&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; ctx&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; TaskOrchestrationContext&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; counter &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;    ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setCustomStatus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;counter&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; monitorEntityId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getInput&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;String&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;java&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; operation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;waitForEntityOperation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;operation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Add&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; counter &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;operation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;input &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; Int&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Reset&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; counter &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setCustomStatus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;counter&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;counter &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; responseOperation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Operation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Update&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; input &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; counter&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; signalInput &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;SignalEntityInput&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;monitorEntityId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; responseOperation&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;            ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;callActivity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;SignalEntity&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; signalInput&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The counter now receives the monitor&#39;s ID as input and signals it when reaching key milestones.
Instead of handling the signaling directly, it delegates the task to the activity function, ensuring
orchestration constraints are respected.&lt;/p&gt;
&lt;h2&gt;Defining the Monitor&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;Monitor&lt;/code&gt; entity listens for updates from the &lt;code&gt;Counter&lt;/code&gt; and logs the received progress.&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@FunctionName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Monitor&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;monitor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token annotation builtin&quot;&gt;@DurableOrchestrationTrigger&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ctx&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; ctx&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; TaskOrchestrationContext&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    context&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ExecutionContext&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; operation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;waitForEntityOperation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;operation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Update&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;logger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Progress update: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;operation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;input&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;%&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By continuously listening for updates, the monitor keeps track of milestones reached by the counter.&lt;/p&gt;
&lt;h2&gt;Initializing Both Entities via HTTP&lt;/h2&gt;
&lt;p&gt;To establish communication between the &lt;code&gt;Counter&lt;/code&gt; and &lt;code&gt;Monitor&lt;/code&gt;, we define an HTTP function that
creates both entities in a single request. The monitor is created first, and its ID is passed to the
counter.&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@FunctionName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;CreateMonitorAndCounter&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createMonitorAndCounter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token annotation builtin&quot;&gt;@HttpTrigger&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;        name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;req&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        methods &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;HttpMethod&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;GET&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        authLevel &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; AuthorizationLevel&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ANONYMOUS&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    request&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; HttpRequestMessage&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Optional&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;String&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token annotation builtin&quot;&gt;@DurableClientInput&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ctx&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; ctx&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; DurableClientContext&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; HttpResponseMessage &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Create a Monitor and a Counter, passing the monitorId to the counter&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; monitorId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Entity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;client&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Monitor&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; counterId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Entity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;client&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Counter&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; monitorId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Return an HTTP response with the IDs&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; responseBody &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token string-literal multiline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&quot;&lt;br /&gt;        Created Monitor and Counter.&lt;br /&gt;        Monitor ID: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;monitorId&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&lt;br /&gt;        Counter ID: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;counterId&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&lt;br /&gt;    &quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;trimIndent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;success&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;responseBody&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This ensures the counter knows where to send updates.&lt;/p&gt;
&lt;h2&gt;Verifying Cross-Communication&lt;/h2&gt;
&lt;p&gt;We can now verify the &lt;code&gt;Counter&lt;/code&gt; can signal the &lt;code&gt;Monitor&lt;/code&gt; by instantiating them and adding a value of
10 to the counter, triggering the monitored milestone:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;❯ &lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; https://durable-app.azurewebsites.net/api/CreateMonitorAndCounter&lt;br /&gt;Created Monitor and Counter.&lt;br /&gt;Monitor ID: f224fd54-c343-49b6-9305-50e96f6b76d4&lt;br /&gt;Counter ID: e415d7bb-8b6a-4134-a0ba-d81420839657&lt;br /&gt;&lt;br /&gt;❯ &lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; https://durable-app.azurewebsites.net/api/Add&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;?&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;br /&gt;entityId&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;e415d7bb-8b6a-4134-a0ba-d81420839657&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;amount&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;br /&gt;Amount added.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Logs confirm that the &lt;code&gt;Monitor&lt;/code&gt; received the signal:&lt;/p&gt;
&lt;pre class=&quot;language-txt&quot;&gt;&lt;code class=&quot;language-txt&quot;&gt;2024-11-12T12:17:19Z   [Information]   Progress update: 10.0%&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;Counter&lt;/code&gt; and &lt;code&gt;Monitor&lt;/code&gt; are now communicating dynamically.&lt;/p&gt;
&lt;h2&gt;Abstracting Cross-Communication&lt;/h2&gt;
&lt;p&gt;To streamline our implementation, we introduce a helper function for entity signaling.&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; TaskOrchestrationContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;signalEntity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    entityId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    operationName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    operationInput&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Any&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; operation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Operation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; operationName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; input &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; operationInput&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; signalInput &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;SignalEntityInput&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entityId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; operation&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;callActivity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;SignalEntity&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; signalInput&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using this abstraction, we simplify the &lt;code&gt;Counter&lt;/code&gt; entity further:&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;counter &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;signalEntity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;monitorEntityId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Update&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; counter&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This keeps the logic concise and easy to read while ensuring entity signals are handled correctly..&lt;/p&gt;
&lt;h2&gt;What&#39;s Next?&lt;/h2&gt;
&lt;p&gt;Now that our entities can communicate with each other, we can move beyond fire-and-forget signals.&lt;/p&gt;
&lt;p&gt;In the next post, we explore entity calling, allowing entities to send requests and receive
responses, further enhancing their capabilities.&lt;/p&gt;
&lt;h2&gt;Read Further&lt;/h2&gt;
&lt;p&gt;This post is part of the
&lt;a href=&quot;https://nizar.se/implementing-durable-entities-in-kotlin&quot;&gt;Implementing Durable Entities in Kotlin&lt;/a&gt; series.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Previous&lt;/strong&gt;:
&lt;a href=&quot;https://nizar.se/implementing-durable-entities-in-kotlin-signaling-entities-with-input&quot;&gt;Signaling Entities with Input&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Next&lt;/strong&gt;: &lt;a href=&quot;https://nizar.se/implementing-durable-entities-in-kotlin-calling-entities&quot;&gt;Calling Entities&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

    </content>
  </entry>
  <entry>
    <title>Implementing Durable Entities in Kotlin - Signaling Entities with Input</title>
    <link href="https://nizar.se/implementing-durable-entities-in-kotlin-signaling-entities-with-input/"/>
    <updated>2025-01-04T00:00:00Z</updated>
    <id>https://nizar.se/implementing-durable-entities-in-kotlin-signaling-entities-with-input/</id>
    <link rel="enclosure" type="image/jpeg" href="https://nizar.se/uploads/chess.jpg" />
    <content type="html">
      &lt;img src="https://nizar.se/uploads/chess.jpg" alt="Black and white chess pieces on a blurred background." /&gt;
      &lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;So far, we have implemented signaling to interact with entities dynamically, allowing our counter to
respond to operations like increment and reset. However, these signals have been limited to simple
operation names, restricting flexibility.&lt;/p&gt;
&lt;p&gt;In this post, we extend our signaling mechanism to support input data, enabling more complex
interactions. By passing structured data with each signal, we allow operations like adding a
specific amount to the counter. With this enhancement, our counter entity will support more
realistic interactions, moving closer to the flexibility required in real-world applications.&lt;/p&gt;
&lt;h2&gt;Passing Input with Signals&lt;/h2&gt;
&lt;h3&gt;Defining a Data Model for Operations&lt;/h3&gt;
&lt;p&gt;Instead of sending plain operation names, we define a structured &lt;code&gt;Operation&lt;/code&gt; data class that
includes both an operation type and optional input. Since Durable Functions use Jackson for
serialization, we follow the same approach for consistency.&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; objectMapper &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;jacksonObjectMapper&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Operation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; input&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Any&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This allows signals to carry additional information, such as an integer to modify the counter.&lt;/p&gt;
&lt;h3&gt;Updating the SignalEntity Function&lt;/h3&gt;
&lt;p&gt;To handle structured input, we modify the &lt;code&gt;signalEntity&lt;/code&gt; function to send JSON-encoded operations.&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; DurableTaskClient&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;signalEntity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    entityId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    operationName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    operationInput&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Any&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; operation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Operation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; operationName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; input &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; operationInput&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; operationJSON &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; objectMapper&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;writeValueAsString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;operation&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;raiseEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entityId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;EntityOperation&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; operationJSON&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This ensures that every entity receives structured events, making event-driven interactions more
powerful.&lt;/p&gt;
&lt;h2&gt;Handling Input in The Counter Entity&lt;/h2&gt;
&lt;h3&gt;Processing Events with Data Input&lt;/h3&gt;
&lt;p&gt;We modify the &lt;code&gt;Counter&lt;/code&gt; entity to parse structured signals and apply operations accordingly.&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@FunctionName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Counter&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@DurableOrchestrationTrigger&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ctx&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; ctx&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; TaskOrchestrationContext&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; counter &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;    ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setCustomStatus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;counter&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; operationJson &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;waitForExternalEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;EntityOperation&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; String&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;java&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; operation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; objectMapper&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;readValue&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Operation&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;operationJson&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;operation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Increment&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; counter&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Add&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; counter &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;operation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;input &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; Int&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Reset&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; counter &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setCustomStatus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;counter&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, the counter can increment by one, add a custom value, or reset based on structured input.&lt;/p&gt;
&lt;h2&gt;Sending Input from an HTTP Function&lt;/h2&gt;
&lt;p&gt;To take advantage of this functionality, we introduce an HTTP function that allows users to specify
an amount to be added to the counter.&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@FunctionName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Add&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token annotation builtin&quot;&gt;@HttpTrigger&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;        name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;req&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        methods &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;HttpMethod&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;GET&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        authLevel &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; AuthorizationLevel&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ANONYMOUS&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    request&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; HttpRequestMessage&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Optional&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;String&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token annotation builtin&quot;&gt;@DurableClientInput&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ctx&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; ctx&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; DurableClientContext&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; HttpResponseMessage &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; entityId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;queryParameters&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;entityId&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token operator&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;badRequest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;entityId required&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; amount &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;queryParameters&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;amount&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token operator&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;badRequest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;amount required&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;signalEntity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entityId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Add&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; amount&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toInt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;success&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Amount added.&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This function extracts the &lt;code&gt;entityId&lt;/code&gt; and &lt;code&gt;amount&lt;/code&gt; from the request, signals the entity with the
provided value, and finally returns a success message.&lt;/p&gt;
&lt;h2&gt;Testing the Implementation&lt;/h2&gt;
&lt;p&gt;With everything in place, we can now verify that the &lt;code&gt;Add&lt;/code&gt; function correctly updates the counter.&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;❯ &lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; https://durable-app.azurewebsites.net/api/Create&lt;br /&gt;Created Counter with ID: &lt;span class=&quot;token number&quot;&gt;42587159&lt;/span&gt;-ca0e-4342-8514-2cdeee214953&lt;br /&gt;&lt;br /&gt;❯ &lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; https://durable-app.azurewebsites.net/api/Add&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;?&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;br /&gt;entityId&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;42587159&lt;/span&gt;-ca0e-4342-8514-2cdeee214953&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;amount&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;&lt;br /&gt;Amount added.&lt;br /&gt;&lt;br /&gt;❯ &lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; https://durable-app.azurewebsites.net/api/Get&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;?&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;br /&gt;entityId&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;42587159&lt;/span&gt;-ca0e-4342-8514-2cdeee214953&lt;br /&gt;Counter value: &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;❯ &lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; https://durable-app.azurewebsites.net/api/Add&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;?&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;br /&gt;entityId&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;42587159&lt;/span&gt;-ca0e-4342-8514-2cdeee214953&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;amount&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;br /&gt;Amount added.&lt;br /&gt;&lt;br /&gt;❯ &lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; https://durable-app.azurewebsites.net/api/Get&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;?&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;br /&gt;entityId&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;42587159&lt;/span&gt;-ca0e-4342-8514-2cdeee214953&lt;br /&gt;Counter value: &lt;span class=&quot;token number&quot;&gt;9&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The counter correctly updates based on the values provided.&lt;/p&gt;
&lt;h2&gt;Refactoring for Cleaner Event Handling&lt;/h2&gt;
&lt;h3&gt;Simplifying Event Handling with a Helper Function&lt;/h3&gt;
&lt;p&gt;To streamline the counter&#39;s logic, we introduce a helper function that waits for and parses incoming
operations:&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; TaskOrchestrationContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;waitForEntityOperation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Operation &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; json &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;waitForExternalEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;EntityOperation&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; String&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;java&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; objectMapper&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;readValue&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Operation&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;json&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Refactoring the Counter Entity&lt;/h3&gt;
&lt;p&gt;Using this helper function, we simplify our counter implementation.&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@FunctionName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Counter&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@DurableOrchestrationTrigger&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ctx&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; ctx&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; TaskOrchestrationContext&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; counter &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;    ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setCustomStatus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;counter&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; operation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;waitForEntityOperation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;operation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Add&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; counter &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;operation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;input &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; Int&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Reset&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; counter &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setCustomStatus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;counter&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This update eliminates unnecessary JSON parsing within the main loop, keeping the entity concise and
readable.&lt;/p&gt;
&lt;h2&gt;What&#39;s Next?&lt;/h2&gt;
&lt;p&gt;Now that our entities can process structured signals, they are no longer limited to basic state
changes but can dynamically react to user input. In the next post, we will explore cross-entity
communication, enabling entities to interact with each other, further expanding the scope of what we
can build.&lt;/p&gt;
&lt;h2&gt;Read Further&lt;/h2&gt;
&lt;p&gt;This post is part of the
&lt;a href=&quot;https://nizar.se/implementing-durable-entities-in-kotlin&quot;&gt;Implementing Durable Entities in Kotlin&lt;/a&gt; series.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Previous&lt;/strong&gt;: &lt;a href=&quot;https://nizar.se/implementing-durable-entities-in-kotlin-signaling-entities&quot;&gt;Signaling Entities&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Next&lt;/strong&gt;: &lt;a href=&quot;https://nizar.se/implementing-durable-entities-in-kotlin-cross-communication&quot;&gt;Cross-Communication&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

    </content>
  </entry>
  <entry>
    <title>Implementing Durable Entities in Kotlin - Signaling Entities</title>
    <link href="https://nizar.se/implementing-durable-entities-in-kotlin-signaling-entities/"/>
    <updated>2025-01-03T00:00:00Z</updated>
    <id>https://nizar.se/implementing-durable-entities-in-kotlin-signaling-entities/</id>
    <link rel="enclosure" type="image/jpeg" href="https://nizar.se/uploads/chess.jpg" />
    <content type="html">
      &lt;img src="https://nizar.se/uploads/chess.jpg" alt="Black and white chess pieces on a blurred background." /&gt;
      &lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;So far, we have created an entity that stores state using custom status, but it remains static. Once
created, there is no way to interact with it or modify its state dynamically. In real-world
applications, stateful objects must react to external inputs.&lt;/p&gt;
&lt;p&gt;This is where event-driven updates come in.&lt;/p&gt;
&lt;p&gt;In this post, we introduce signaling, a mechanism of sending one-way (fire-and-forget) messages to
an entity. By enabling our counter to listen for external events, we allow it to dynamically update
its state in response to operations like increment and reset.&lt;/p&gt;
&lt;h2&gt;Signaling vs. Calling&lt;/h2&gt;
&lt;p&gt;Entities can be accessed in two ways, as explained in the
&lt;a href=&quot;https://learn.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-entities?tabs=function-based%2Cin-process%2Cpython-v2&amp;amp;pivots=csharp#access-entities&quot;&gt;Durable Entities documentation&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Signaling&lt;/strong&gt; Sends an operation without waiting for a response. It is best suited for updates
that do not require immediate feedback.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Calling&lt;/strong&gt; Sends an operation and waits for a result before continuing. This is useful when you
need to retrieve values from an entity.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this post, we will focus on signaling and by the end of it our counter entity will become
interactive, responding to external requests.&lt;/p&gt;
&lt;h2&gt;Extending the Counter to Handle Events&lt;/h2&gt;
&lt;p&gt;To enable event-driven updates, we modify the &lt;code&gt;Counter&lt;/code&gt; orchestration so that it listens for
incoming events. It will wait for external signals and update its state accordingly.&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@FunctionName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Counter&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@DurableOrchestrationTrigger&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ctx&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; ctx&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; TaskOrchestrationContext&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Initialize the counter value and the custom status&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; counter &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;    ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setCustomStatus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;counter&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// Wait for an external event&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; operation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;waitForExternalEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;EntityOperation&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; String&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;java&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// Process the requested operation&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;operation&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Increment&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; counter&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Increase counter by 1&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Reset&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; counter &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;   &lt;span class=&quot;token comment&quot;&gt;// Reset counter to 0&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// Update the stored state with the new value&lt;/span&gt;&lt;br /&gt;        ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setCustomStatus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;counter&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, instead of being static, the counter remains active, continuously listening for events. When it
receives an operation, it updates its state and waits for the next event.&lt;/p&gt;
&lt;p&gt;At this point, the counter can respond to external events, but we still need a way to send these
signals.&lt;/p&gt;
&lt;h2&gt;Sending Signals to the Counter&lt;/h2&gt;
&lt;p&gt;To interact with the counter, we create HTTP-triggered functions that send events to a specific
instance.&lt;/p&gt;
&lt;h3&gt;Increment Operation&lt;/h3&gt;
&lt;p&gt;This function sends an event to increase the counter value.&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@FunctionName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Increment&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;increment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token annotation builtin&quot;&gt;@HttpTrigger&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;        name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;req&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        methods &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;HttpMethod&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;GET&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        authLevel &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; AuthorizationLevel&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ANONYMOUS&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    request&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; HttpRequestMessage&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Optional&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;String&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token annotation builtin&quot;&gt;@DurableClientInput&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ctx&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; ctx&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; DurableClientContext&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; HttpResponseMessage &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Extract the instanceId from query parameters&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; entityId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;queryParameters&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;entityId&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token operator&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;badRequest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;entityId required&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Raise an event to the Counter to increment its value&lt;/span&gt;&lt;br /&gt;    ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;raiseEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;instanceId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;EntityOperation&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Increment&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Return an HTTP response with a helpful message&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;success&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Counter Incremented.&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Reset Operation&lt;/h3&gt;
&lt;p&gt;This function sends an event to reset the counter to 0.&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@FunctionName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Reset&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;increment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token annotation builtin&quot;&gt;@HttpTrigger&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;        name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;req&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        methods &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;HttpMethod&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;GET&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        authLevel &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; AuthorizationLevel&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ANONYMOUS&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    request&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; HttpRequestMessage&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Optional&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;String&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token annotation builtin&quot;&gt;@DurableClientInput&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ctx&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; ctx&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; DurableClientContext&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; HttpResponseMessage &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Extract the instanceId from query parameters&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; entityId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;queryParameters&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;entityId&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token operator&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;badRequest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;entityId required&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Raise an event to the Counter to reset its value&lt;/span&gt;&lt;br /&gt;    ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;raiseEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;instanceId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;EntityOperation&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Reset&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Return an HTTP response with a helpful message&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;success&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Counter Reset.&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Abstracting Signal Logic&lt;/h3&gt;
&lt;p&gt;Right now, we hardcoded the event name &lt;code&gt;EntityOperation&lt;/code&gt; everywhere. This is an implementation
detail and there is no reason to leak into the rest of the code base. We can introduce a helper
function for signaling that will help us clean up our code:&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; DurableTaskClient&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;signalEntity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entityId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; operation&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;raiseEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entityId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;EntityOperation&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; operation&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With our abstraction, the HTTP functions become even cleaner:&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@FunctionName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Increment&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;increment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token annotation builtin&quot;&gt;@HttpTrigger&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;        name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;req&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        methods &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;HttpMethod&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;GET&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        authLevel &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; AuthorizationLevel&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ANONYMOUS&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    request&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; HttpRequestMessage&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Optional&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;String&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token annotation builtin&quot;&gt;@DurableClientInput&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ctx&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; ctx&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; DurableClientContext&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; HttpResponseMessage &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; entityId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;queryParameters&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;entityId&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token operator&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;badRequest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;entityId required&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;signalEntity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entityId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Increment&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;success&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Counter Incremented.&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This makes signaling cleaner and more intuitive, matching how Durable Entities are used in other
languages.&lt;/p&gt;
&lt;h2&gt;Verifying the Implementation&lt;/h2&gt;
&lt;p&gt;With everything in place, we can now verify that our counter responds to events.&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;❯ &lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; https://durable-app.azurewebsites.net/api/Create&lt;br /&gt;Created Counter with ID: b13e7165-6ee4-4429-9295-a5f998d9881d&lt;br /&gt;&lt;br /&gt;❯ &lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; https://durable-app.azurewebsites.net/api/Get&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;?&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;br /&gt;entityId&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;b13e7165-6ee4-4429-9295-a5f998d9881d&lt;br /&gt;Counter value: &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;❯ &lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; https://durable-app.azurewebsites.net/api/Increment&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;?&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;br /&gt;entityId&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;b13e7165-6ee4-4429-9295-a5f998d9881d&lt;br /&gt;Counter Incremented.&lt;br /&gt;&lt;br /&gt;❯ &lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; https://durable-app.azurewebsites.net/api/Get&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;?&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;br /&gt;entityId&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;b13e7165-6ee4-4429-9295-a5f998d9881d&lt;br /&gt;Counter value: &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;❯ &lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; https://durable-app.azurewebsites.net/api/Reset&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;?&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;br /&gt;entityId&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;b13e7165-6ee4-4429-9295-a5f998d9881d&lt;br /&gt;Counter Reset.&lt;br /&gt;&lt;br /&gt;❯ &lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; https://durable-app.azurewebsites.net/api/Get&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;?&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;br /&gt;entityId&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;b13e7165-6ee4-4429-9295-a5f998d9881d&lt;br /&gt;Counter value: &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this, we have successfully made our counter interactive. It now listens for external events and
updates its state dynamically.&lt;/p&gt;
&lt;h2&gt;What&#39;s Next?&lt;/h2&gt;
&lt;p&gt;Now that we can send one-way messages to update an entity, the next step is to make these signals
more powerful.&lt;/p&gt;
&lt;p&gt;In the next post, we will extend signaling to support input parameters, allowing entities to process
structured commands rather than just operation names.&lt;/p&gt;
&lt;h2&gt;Read Further&lt;/h2&gt;
&lt;p&gt;This post is part of the
&lt;a href=&quot;https://nizar.se/implementing-durable-entities-in-kotlin&quot;&gt;Implementing Durable Entities in Kotlin&lt;/a&gt; series.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Previous&lt;/strong&gt;: &lt;a href=&quot;https://nizar.se/implementing-durable-entities-in-kotlin-creating-entities&quot;&gt;Creating Entities&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Next&lt;/strong&gt;:
&lt;a href=&quot;https://nizar.se/implementing-durable-entities-in-kotlin-signaling-entities-with-input&quot;&gt;Signaling Entities with Input&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

    </content>
  </entry>
  <entry>
    <title>Implementing Durable Entities in Kotlin - Creating Entities</title>
    <link href="https://nizar.se/implementing-durable-entities-in-kotlin-creating-entities/"/>
    <updated>2025-01-02T00:00:00Z</updated>
    <id>https://nizar.se/implementing-durable-entities-in-kotlin-creating-entities/</id>
    <link rel="enclosure" type="image/jpeg" href="https://nizar.se/uploads/chess.jpg" />
    <content type="html">
      &lt;img src="https://nizar.se/uploads/chess.jpg" alt="Black and white chess pieces on a blurred background." /&gt;
      &lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;So far, we have seen how Durable Entities persist state across executions and conserve resources. We
have used custom status and metadata to store and retrieve state for a basic Counter entity.
However, to interact with entities efficiently, we need a structured way to identify and reference
them.&lt;/p&gt;
&lt;p&gt;This post introduce Entity IDs, which uniquely identify specific instances of an entity. To make
instance creation simpler and more intuitive, we also introduce a lightweight abstraction that
aligns with how Durable Entities are created in other languages.&lt;/p&gt;
&lt;h2&gt;Understanding Entity IDs&lt;/h2&gt;
&lt;p&gt;When working with Durable Entities, each instance must be uniquely identifiable. According to the
&lt;a href=&quot;https://learn.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-entities?tabs=function-based%2Cin-process%2Cpython-v2&amp;amp;pivots=csharp#entity-id&quot;&gt;Durable Entities documentation&lt;/a&gt;,
an entity ID consists of an entity name, which represents the type of the entity, and an entity key,
which uniquely identifies a specific instance.&lt;/p&gt;
&lt;p&gt;This structure enables the creation of multiple instances of the same entity while keeping them
distinct. For example, in C#, an entity ID for a counter entity can be created like this:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code class=&quot;language-csharp&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt;&lt;/span&gt; entityId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token constructor-invocation class-name&quot;&gt;EntityId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;nameof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Counter&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;myCounter&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, &lt;code&gt;Counter&lt;/code&gt; is the entity name, and &lt;code&gt;myCounter&lt;/code&gt; is the key that uniquely identifies this
instance.&lt;/p&gt;
&lt;p&gt;With this approach, we can reference and interact with specific entities in a structured way.&lt;/p&gt;
&lt;h2&gt;Abstracting Entity Creation&lt;/h2&gt;
&lt;h3&gt;Why introduce an Abstraction?&lt;/h3&gt;
&lt;p&gt;Right now, we manually schedule an orchestration each time we create an entity. While this approach
works, it exposes unnecessary implementation details. Instead of handling entity creating explicitly
in each function, we can introduce an abstraction that simplifies the process.&lt;/p&gt;
&lt;p&gt;Encapsulating entity creation in a dedicated class makes instance creation more intuitive, aligns
with Durable Entities in other languages, and keeps the code cleaner.&lt;/p&gt;
&lt;h3&gt;Implementing the Entity Class&lt;/h3&gt;
&lt;p&gt;To achieve this, we define an &lt;code&gt;Entity&lt;/code&gt; class that takes an entity name, and optional key to
distinguish instances, and an optional input parameter. It uses DurableTaskClient to schedule an
orchestration and returns the instance ID.&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; Entity&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    client&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; DurableTaskClient&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    key&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    input&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Any&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Create an instance of the requested Entity&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; instanceId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;scheduleNewOrchestrationInstance&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; input&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Factory method for entity creation&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;companion&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;invoke&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;            client&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; DurableTaskClient&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            input&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Any&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            key&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; entity &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Entity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;client&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; input&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; entity&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;instanceId&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this abstraction in place, creating an entity instance is now as simple as:&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; entityId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Entity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;client&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Counter&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;myCounter&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At this stage, we return the instance ID, but we could modify it to return a formatted string like
&lt;code&gt;@Counter@Game1&lt;/code&gt; to align more closely with the native implementation.&lt;/p&gt;
&lt;p&gt;Note that we have also added an input parameter as well. We will use this later when we want to
provide input to an entity when we instantiate it.&lt;/p&gt;
&lt;h2&gt;Refactoring the Create Function&lt;/h2&gt;
&lt;p&gt;With the new abstraction, we can simplify our &lt;code&gt;Create&lt;/code&gt; function:&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@FunctionName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Create&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token annotation builtin&quot;&gt;@HttpTrigger&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;        name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;req&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        methods &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;HttpMethod&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;GET&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        authLevel &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; AuthorizationLevel&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ANONYMOUS&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    request&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; HttpRequestMessage&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Optional&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;String&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token annotation builtin&quot;&gt;@DurableClientInput&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ctx&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; ctx&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; DurableClientContext&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; HttpResponseMessage &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Create a new Counter instance with a specific key&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; entityId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Entity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;client&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Counter&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;myCounter&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Return an HTTP response containing the entity ID&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; request&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createResponseBuilder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HttpStatus&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;OK&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Created Counter with ID: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;entityId&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;\n&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This keeps the code focused on the business logic rather than exposing orchestration details.&lt;/p&gt;
&lt;h2&gt;Simplifying HTTP Handling&lt;/h2&gt;
&lt;p&gt;Since we will be handling multiple HTTP-triggered functions, we can reduce repetitive
response-handling code by introducing two extension functions:&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; HttpRequestMessage&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Optional&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;String&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;badRequest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; HttpResponseMessage &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;createResponseBuilder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HttpStatus&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;BAD_REQUEST&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;message&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; HttpRequestMessage&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Optional&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;String&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;success&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; HttpResponseMessage &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;createResponseBuilder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HttpStatus&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;OK&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;message&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using these, our &lt;code&gt;Create&lt;/code&gt; function becomes even cleaner:&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@FunctionName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Create&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token annotation builtin&quot;&gt;@HttpTrigger&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;        name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;req&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        methods &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;HttpMethod&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;GET&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        authLevel &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; AuthorizationLevel&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ANONYMOUS&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    request&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; HttpRequestMessage&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Optional&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;String&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token annotation builtin&quot;&gt;@DurableClientInput&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ctx&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; ctx&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; DurableClientContext&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; HttpResponseMessage &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; entityId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Entity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;client&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Counter&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;myCounter&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;success&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Created Counter with ID: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;entityId&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;\n&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This reduces clutter and makes the functions easier to read.&lt;/p&gt;
&lt;h2&gt;What&#39;s Next?&lt;/h2&gt;
&lt;p&gt;With Entity IDs in place, we now have a structured way to create and reference Durable Entities. The
next step is to make these entities interactive by introducing event-driven updates.&lt;/p&gt;
&lt;p&gt;In the next post, we will explore signaling, a mechanism that allows sending operations to entities
without awaiting a response.&lt;/p&gt;
&lt;h2&gt;Read Further&lt;/h2&gt;
&lt;p&gt;This post is part of the
&lt;a href=&quot;https://nizar.se/implementing-durable-entities-in-kotlin&quot;&gt;Implementing Durable Entities in Kotlin&lt;/a&gt; series.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Previous&lt;/strong&gt;: &lt;a href=&quot;https://nizar.se/implementing-durable-entities-in-kotlin-persisting-state&quot;&gt;Persisting State&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Next&lt;/strong&gt;: &lt;a href=&quot;https://nizar.se/implementing-durable-entities-in-kotlin-signaling-entities&quot;&gt;Signaling Entities&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

    </content>
  </entry>
  <entry>
    <title>Implementing Durable Entities in Kotlin - Persisting State</title>
    <link href="https://nizar.se/implementing-durable-entities-in-kotlin-persisting-state/"/>
    <updated>2025-01-01T00:00:00Z</updated>
    <id>https://nizar.se/implementing-durable-entities-in-kotlin-persisting-state/</id>
    <link rel="enclosure" type="image/jpeg" href="https://nizar.se/uploads/chess.jpg" />
    <content type="html">
      &lt;img src="https://nizar.se/uploads/chess.jpg" alt="Black and white chess pieces on a blurred background." /&gt;
      &lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Durable Entities provide a way to model long-lived, stateful objects in serverless workflows, but
they aren&#39;t natively supported in Kotlin. In the
&lt;a href=&quot;https://nizar.se/implementing-durable-entities-in-kotlin/&quot;&gt;previous post&lt;/a&gt;, we introduced Durable Entities and
explored their key principles, such as event sourcing and deterministic execution.&lt;/p&gt;
&lt;p&gt;A fundamental requirement of Durable Entities is persisting state across executions to ensure
entities remain functional between invocations. Since Durable Entities aren&#39;t available in Kotlin,
we can achieve this using custom status metadata, a built-in feature of Durable Orchestrations that
allows storing arbitrary state tied to an instance.&lt;/p&gt;
&lt;p&gt;This post demonstrates how to persist and retrieve state using custom status. We will walk through
initializing and reading the state of a Counter entity, establishing a foundation for more advanced
features in later posts.&lt;/p&gt;
&lt;h2&gt;Persisting State in an Orchestration&lt;/h2&gt;
&lt;p&gt;The first step in making an entity stateful is to ensure it can store and retain values between
executions. We define a Counter orchestration that initializes a stored value.&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@FunctionName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Counter&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@DurableOrchestrationTrigger&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ctx&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; ctx&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; TaskOrchestrationContext&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Set initial value&lt;/span&gt;&lt;br /&gt;    ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setCustomStatus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This function initializes a Counter entity and assigns it a starting value of 0 using
&lt;code&gt;ctx.setCustomStatus(0)&lt;/code&gt;. The orchestration is currently static as it stores a value but does not
yet support modifications to it. In later posts, we will extend it to allow updates through external
inputs.&lt;/p&gt;
&lt;h2&gt;Creating An Orchestration Instance&lt;/h2&gt;
&lt;p&gt;Before interacting with the Counter, we need to create instances of it. In Durable Functions,
orchestrations are typically instantiated using HTTP-triggered functions, which allow external
systems to create and manage them on demand.&lt;/p&gt;
&lt;p&gt;The following function starts a new instance of the Counter orchestration:&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@FunctionName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Create&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token annotation builtin&quot;&gt;@HttpTrigger&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;        name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;req&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        methods &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;HttpMethod&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;GET&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        authLevel &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; AuthorizationLevel&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ANONYMOUS&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    request&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; HttpRequestMessage&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Optional&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;String&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token annotation builtin&quot;&gt;@DurableClientInput&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ctx&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; ctx&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; DurableClientContext&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; HttpResponseMessage &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Start a new Counter instance&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; instanceId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;scheduleNewOrchestrationInstance&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Counter&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Return the instance ID so we can interact with it later&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; request&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createResponseBuilder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HttpStatus&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;OK&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Created Counter with ID: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;instanceId&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;\n&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The function starts an orchestration by calling &lt;code&gt;scheduleNewOrchestrationInstance(&amp;quot;Counter&amp;quot;)&lt;/code&gt; and
returns the generated instance ID which will be used later to interact with it. We can now create a
counter instance using &lt;code&gt;curl&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;❯ &lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; https://durable-app.azurewebsites.net/api/Create&lt;br /&gt;Created Counter with ID: 9864a3e8-4f01-4201-8920-0b628c739bee&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At this point, we have an instance that persists state, but we need a way to retrieve its stored
value.&lt;/p&gt;
&lt;h2&gt;Retrieving State from the Orchestration&lt;/h2&gt;
&lt;p&gt;To fetch the stored value of the Counter, we define another HTTP-triggered function:&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@FunctionName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Get&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token annotation builtin&quot;&gt;@HttpTrigger&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;        name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;req&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        methods &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;HttpMethod&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;GET&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        authLevel &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; AuthorizationLevel&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ANONYMOUS&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    request&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; HttpRequestMessage&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Optional&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;String&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token annotation builtin&quot;&gt;@DurableClientInput&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ctx&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; ctx&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; DurableClientContext&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; HttpResponseMessage &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Extract instanceId from query parameters&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; instanceId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;queryParameters&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;instanceId&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token operator&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createResponseBuilder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HttpStatus&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;BAD_REQUEST&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;instanceId required\n&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Retrieve the counter value from custom status&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; counterValue &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;client&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getInstanceMetadata&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;instanceId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;readCustomStatusAs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Int&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;java&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Return the current counter value&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createResponseBuilder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HttpStatus&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;OK&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Counter value: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;counterValue&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;\n&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This function looks up an orchestration instance by its &lt;code&gt;instanceId&lt;/code&gt;, retrieves its stored custom
status, and returns the current counter value. To make the retrieval logic more reusable and
maintainable, we introduce an extension function:&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;T&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; DurableTaskClient&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getEntityState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entityId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; returnType&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Class&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;T&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; T&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getInstanceMetadata&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entityId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;readCustomStatusAs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;returnType&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this abstraction, our &lt;code&gt;Get&lt;/code&gt; function becomes cleaner and more intuitive:&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@FunctionName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Get&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token annotation builtin&quot;&gt;@HttpTrigger&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;        name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;req&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        methods &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;HttpMethod&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;GET&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        authLevel &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; AuthorizationLevel&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ANONYMOUS&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    request&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; HttpRequestMessage&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Optional&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;String&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token annotation builtin&quot;&gt;@DurableClientInput&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ctx&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; ctx&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; DurableClientContext&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; HttpResponseMessage &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Get entityId from request query parameters&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; entity &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;queryParameters&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;entityId&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token operator&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;badRequest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;entityId required&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Get the state of the Counter entity as an Int&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; counterValue &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getEntityState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entity&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Int&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;java&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Return an HTTP response containing counter&#39;s current value&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createResponseBuilder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HttpStatus&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;OK&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Counter value: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;counterValue&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;\n&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This approach hides implementation details, keeping our code readable.&lt;/p&gt;
&lt;h2&gt;Verifying State Persistence&lt;/h2&gt;
&lt;p&gt;Now that we can create and retrieve a counter instance, let us verify that the state persists:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;❯ &lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; https://durable-app.azurewebsites.net/api/Create&lt;br /&gt;Created Counter with ID: af842648-5ffe-4be3-bb17-27aabf303dcb&lt;br /&gt;&lt;br /&gt;❯ &lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; https://durable-app.azurewebsites.net/api/Get&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;?&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;br /&gt;entityId&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;af842648-5ffe-4be3-bb17-27aabf303dcb&lt;br /&gt;Counter value: &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The counter instance correctly initializes and maintains its state. Even if we rerun the second
command hours or days later, it will still return the same value. This persistence will become more
evident when we introduce event-driven updates in later posts.&lt;/p&gt;
&lt;h2&gt;What&#39;s Next?&lt;/h2&gt;
&lt;p&gt;Now that our Counter entity can persists state, the next step is refine its structure. Before making
it interactive, we need a better way to reference and manage instances. In the next post, we
introduce Entity IDs, which provide a structured way to uniquely identify entities while also
abstracting orchestration scheduling.&lt;/p&gt;
&lt;h2&gt;Read Further&lt;/h2&gt;
&lt;p&gt;This post is part of the
&lt;a href=&quot;https://nizar.se/implementing-durable-entities-in-kotlin&quot;&gt;Implementing Durable Entities in Kotlin&lt;/a&gt; series.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Previous&lt;/strong&gt;: &lt;a href=&quot;https://nizar.se/implementing-durable-entities-in-kotlin&quot;&gt;Series Introduction&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Next&lt;/strong&gt;: &lt;a href=&quot;https://nizar.se/implementing-durable-entities-in-kotlin-creating-entities&quot;&gt;Creating Entities&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

    </content>
  </entry>
  <entry>
    <title>Implementing Durable Entities in Kotlin</title>
    <link href="https://nizar.se/implementing-durable-entities-in-kotlin/"/>
    <updated>2024-11-19T00:00:00Z</updated>
    <id>https://nizar.se/implementing-durable-entities-in-kotlin/</id>
    <link rel="enclosure" type="image/jpeg" href="https://nizar.se/uploads/chess.jpg" />
    <content type="html">
      &lt;img src="https://nizar.se/uploads/chess.jpg" alt="Black and white chess pieces on a blurred background." /&gt;
      &lt;p&gt;I&#39;ve been fortunate to work with some of the &lt;a href=&quot;https://factor10.com/&quot;&gt;greatest minds&lt;/a&gt; early in my
career, an opportunity I&#39;m endlessly grateful for. Over the past year, I&#39;ve worked with Erik Meijer
on &lt;a href=&quot;https://fortune.com/2024/04/02/mark-zuckerberg-ai-jobs-meta-brain-drain-erik-meijer/&quot;&gt;Automind&lt;/a&gt;,
tackling some truly exciting challenges.&lt;/p&gt;
&lt;p&gt;This experience introduced me to Durable Functions, an abstraction that simplifies building stateful
workflows in serverless environments. Among its many features, Durable Entities stands out by
enabling developers to model stateful objects that manage their own state.&lt;/p&gt;
&lt;p&gt;However, there&#39;s a catch: Durable Entities aren&#39;t supported in Kotlin or Java. Knowing Erik,
suggesting another language was out of the question. This set the stage for my challenge:
implementing Durable Entities in Kotlin.&lt;/p&gt;
&lt;h2&gt;What are Durable Entities?&lt;/h2&gt;
&lt;p&gt;Before diving into implementation, let&#39;s first understand Durable Entities. They enable applications
to persist state across executions, conserve resources when idle, and seamlessly resume workflows
when needed. This makes them particularly valuable in scenarios like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Event-driven architectures.&lt;/li&gt;
&lt;li&gt;Interaction-based workflows.&lt;/li&gt;
&lt;li&gt;Distributed workflows.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In essence, Durable Entities behave like long-lived, lightweight actors. They preserve their state
using event sourcing, a pattern where state changes are logged as events, allowing state to be
reconstructed by replaying these events. Entities also execute operations deterministically,
ensuring consistency even in distributed environments.&lt;/p&gt;
&lt;p&gt;For example, the official C# documentation provides a simple counter entity, which maintains a value
and supports operations like adding, resetting, and retrieving the current value:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code class=&quot;language-csharp&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token attribute&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;FunctionName&lt;/span&gt;&lt;span class=&quot;token attribute-arguments&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Counter&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token return-type class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Counter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token attribute&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;EntityTrigger&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;IDurableEntityContext&lt;/span&gt; ctx&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;OperationName&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ToLowerInvariant&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token string&quot;&gt;&quot;add&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;SetState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token generic-method&quot;&gt;&lt;span class=&quot;token function&quot;&gt;GetState&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token generic-method&quot;&gt;&lt;span class=&quot;token function&quot;&gt;GetInput&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token string&quot;&gt;&quot;reset&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;SetState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token string&quot;&gt;&quot;get&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token generic-method&quot;&gt;&lt;span class=&quot;token function&quot;&gt;GetState&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This functionality is powerful, but replicating it in Kotlin requires a creative approach. Let&#39;s
dive into how that can be achieved.&lt;/p&gt;
&lt;h2&gt;The Challenge and Insight&lt;/h2&gt;
&lt;p&gt;Initially, I explored gRPC and the
&lt;a href=&quot;https://github.com/microsoft/durabletask-protobuf&quot;&gt;durabletask-protobuf&lt;/a&gt; library, inspired by
implementations in other languages. While this approach was promising, it wasn&#39;t successful.&lt;/p&gt;
&lt;p&gt;A critical insight came from &lt;a href=&quot;https://github.com/cgillum&quot;&gt;Chris Gillum&lt;/a&gt;, the creator of Durable
Functions, who highlighted that Durable Entities are
&lt;a href=&quot;https://github.com/microsoft/durabletask-java/issues/194#issuecomment-2397984973&quot;&gt;implemented in other languages using orchestration instances&lt;/a&gt;.
This realization was a turning point, and not long after, I had my first Durable Entity in Kotlin.&lt;/p&gt;
&lt;h2&gt;Introducing the Series&lt;/h2&gt;
&lt;p&gt;This series will guide you through the development process, step by step. Along the way, we&#39;ll
examine the principle and constraints that underpin Durable Entities, ensuring that our
implementation stays true to the design requirements.&lt;/p&gt;
&lt;p&gt;Here&#39;s an example of a counter entity implemented in Kotlin, modeled after the C# example above. It
demonstrates how to define an entity and handle operations like &amp;quot;add&amp;quot;, &amp;quot;reset&amp;quot;, and &amp;quot;get&amp;quot;:&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@FunctionName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Counter&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token annotation builtin&quot;&gt;@DurableOrchestrationTrigger&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ctx&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; ctx&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; TaskOrchestrationContext&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;asEntity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; initialState &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;operationName&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;lowercase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;add&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;getState&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Int&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; getInput&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Int&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;reset&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;get&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;returnResult&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;getState&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Int&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;What&#39;s Next&lt;/h2&gt;
&lt;p&gt;This series will cover the following topics step-by-step:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://nizar.se/implementing-durable-entities-in-kotlin-persisting-state/&quot;&gt;Persisting State&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nizar.se/implementing-durable-entities-in-kotlin-creating-entities/&quot;&gt;Creating Entities&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nizar.se/implementing-durable-entities-in-kotlin-signaling-entities/&quot;&gt;Signaling Entities&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nizar.se/implementing-durable-entities-in-kotlin-signaling-entities-with-input/&quot;&gt;Signaling Entities with Input&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nizar.se/implementing-durable-entities-in-kotlin-cross-communication/&quot;&gt;Cross-Communication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nizar.se/implementing-durable-entities-in-kotlin-calling-entities/&quot;&gt;Calling Entities&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nizar.se/implementing-durable-entities-in-kotlin-final-enhancements/&quot;&gt;Final Enhancements&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Whether you&#39;re already familiar with Durable Functions or exploring stateful serverless workflows
for the first time, this series will offer something for everyone. Stay tuned!&lt;/p&gt;

    </content>
  </entry>
  <entry>
    <title>Supply Chain Security Risks in Static Sites</title>
    <link href="https://nizar.se/supply-chain-security-risks-in-static-sites/"/>
    <updated>2024-09-11T00:00:00Z</updated>
    <id>https://nizar.se/supply-chain-security-risks-in-static-sites/</id>
    <link rel="enclosure" type="image/jpeg" href="https://nizar.se/uploads/shipping-containers.jpg" />
    <content type="html">
      &lt;img src="https://nizar.se/uploads/shipping-containers.jpg" alt="Overhead view of shipping containers in a busy port terminal" /&gt;
      &lt;p&gt;Static sites are perceived as more secure than their dynamic counterparts due to their simplicity
and lack of server-side components. However, this perception can lead to overlooked threats,
particularly those introduced by third-party libraries and services. In this article, we&#39;ll explore
how these vulnerabilities arise and how you can defend your site against them.&lt;/p&gt;
&lt;h2&gt;What Are Static Sites?&lt;/h2&gt;
&lt;p&gt;Static sites consist of pre-rendered HTML, CSS, and JavaScript files that are delivered directly to
the user&#39;s browser. Their appeal lies in their speed, scalability, and cost-effectiveness. By
avoiding server-side processing, static sites improve performance and reduce resource consumption.&lt;/p&gt;
&lt;p&gt;However, many static sites rely on third-party JavaScript libraries or external services for added
functionality, such as form handling or analytics. This introduces supply chain vulnerabilities,
where compromised dependencies become attack vectors.&lt;/p&gt;
&lt;h2&gt;The Threat of Supply Chain Attacks&lt;/h2&gt;
&lt;p&gt;Supply chain attacks occur when third-party code that your site relies on is compromised. One
notorious example is the
&lt;a href=&quot;https://sansec.io/research/polyfill-supply-chain-attack&quot;&gt;Polyfill.io attack&lt;/a&gt;, where malicious code
affected over 100,000 websites. The code redirected users to a sports betting site while evading
detection:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The code has specific protection against reverse engineering, and only activates on specific
mobile devices at specific hours. It also does not activate when it detects an admin user. It also
delays execution when a web analytics service is found, presumably to not end up in the stats.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In another incident, Cloudflare&#39;s CDNJS service exposed up to
&lt;a href=&quot;https://www.bleepingcomputer.com/news/security/critical-cloudflare-cdn-flaw-allowed-compromise-of-12-percent-of-all-sites/&quot;&gt;12% of all websites&lt;/a&gt;
on the internet to potential code injection attacks, showing that even well-regarded Content
Delivery Networks (CDNs) can be vulnerable.&lt;/p&gt;
&lt;h2&gt;Defending Against Supply Chain Attacks&lt;/h2&gt;
&lt;p&gt;Key defenses against supply chain attacks include
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity&quot;&gt;Subresource Integrity&lt;/a&gt;
(SRI) and &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP&quot;&gt;Content Security Policy&lt;/a&gt; (CSP).
These tools work best when used together as part of a layered security approach.&lt;/p&gt;
&lt;h3&gt;Subresource Integrity (SRI)&lt;/h3&gt;
&lt;p&gt;Subresource Integrity (SRI) ensures that fetched resources, such as JavaScript files, haven&#39;t been
tampered with. It does so by comparing the resource&#39;s cryptographic hash to a predefined value. If
there&#39;s a mismatch, the browser blocks the resource from loading, preventing potential malicious
code from executing.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://cdn.example.com/script.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token attr-name&quot;&gt;integrity&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;sha384-abc123...&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token attr-name&quot;&gt;crossorigin&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;anonymous&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, the &lt;code&gt;integrity&lt;/code&gt; attribute includes the hash of the file. This ensures the resource
is unaltered, adding an extra layer of protection for external scripts your site relies on.&lt;/p&gt;
&lt;h3&gt;Content Security Policy (CSP)&lt;/h3&gt;
&lt;p&gt;Content Security Policy (CSP) allows you to define which sources are permitted to load resources
such as scripts, styles, and images. This reduces the risk of code injection by blocking
unauthorized content from running on your site.&lt;/p&gt;
&lt;p&gt;Here is an example of a CSP that restricts script loading to the same domain and a trusted CDN:&lt;/p&gt;
&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Content-Security-Policy: script-src &#39;self&#39; https://cdn.example.com;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can further strengthen your policy with hash-based CSP directives, allowing only scripts with
matching cryptographic hashes to execute, regardless of their source:&lt;/p&gt;
&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Content-Security-Policy: script-src &#39;sha384-abc123...&#39; &#39;sha384-def456...&#39;;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This approach ensures that unauthorized scripts won&#39;t run even if the source is compromised.&lt;/p&gt;
&lt;h3&gt;Addressing Security Threats&lt;/h3&gt;
&lt;p&gt;Using both CSP and SRI together enhances security, as CSP controls where resources can be loaded
from while SRI verifies their integrity. According to the
&lt;a href=&quot;https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html#defense-in-depth&quot;&gt;OWASP CSP Cheat Sheet&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Even on a fully static website, which does not accept any user input, a CSP can be used to enforce
the use of Subresource Integrity (SRI). This can help prevent malicious code from being loaded on
the website if one of the third-party sites hosting JavaScript files (such as analytics scripts)
is compromised.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;CSP and SRI help mitigate common security threats such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cross-Site Scripting (XSS)&lt;/strong&gt;: XSS attacks allow malicious scripts to be injected into your site,
potentially leading to data theft, session hijacking, or unauthorized actions. CSP blocks
unauthorized scripts by restricting which can run.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Clickjacking&lt;/strong&gt;: This attack deceives users into interacting with hidden elements, often
resulting in unintended actions like form submissions or transactions. CSP can prevent
clickjacking by blocking your site from being embedded in iframes, a common method used in such
attacks.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Site Defacement&lt;/strong&gt;: Attackers may try to alter content on your website, damaging its credibility.
A combination of CSP and SRI ensures that only authorized content is loaded, significantly
reducing the risk of defacement.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Best Practices for CSP Implementation&lt;/h3&gt;
&lt;p&gt;Despite CSP&#39;s effectiveness, it remains underutilized. A
&lt;a href=&quot;https://www.rapid7.com/blog/post/2020/11/02/overview-of-content-security-policies-csp-on-the-web/&quot;&gt;2020 survey&lt;/a&gt;
of the Alexa Top 1 Million websites found that only 7% had a valid CSP, and a
&lt;a href=&quot;https://www.bitsight.com/blog/content-security-policy-limits-dangerous-activity-so-why-isnt-everyone-doing-it&quot;&gt;Bitsight study&lt;/a&gt;
revealed only 2% of 5 million web applications were fully secure.&lt;/p&gt;
&lt;p&gt;To fully leverage CSP, follow these best practices:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Use a strict default policy&lt;/strong&gt;: Start with &lt;code&gt;default-src &#39;none&#39;&lt;/code&gt; and then explicitly allow trusted
sources.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Apply restrictions to all sources&lt;/strong&gt;: Use &lt;code&gt;style-src&lt;/code&gt;, &lt;code&gt;media-src&lt;/code&gt;, and other directives to
tightly control which external resources are loaded.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Avoid unsafe directives&lt;/strong&gt;: Directives like &lt;code&gt;unsafe-inline&lt;/code&gt; and &lt;code&gt;unsafe-eval&lt;/code&gt; can undermine your
policy by allowing inline scripts and styles.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prevent clickjacking&lt;/strong&gt;: Use &lt;code&gt;frame-ancestors&lt;/code&gt; to block other sites from embedding your content
in iframes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Test with reporting&lt;/strong&gt;: Before enforcing CSP, use &lt;code&gt;report-only&lt;/code&gt; mode to monitor violations
without disrupting functionality.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Automating Security Practices&lt;/h2&gt;
&lt;p&gt;Managing CSP manually can be error-prone, so automation tools are invaluable for maintaining
consistent enforcement without burdening your workflow. At &lt;a href=&quot;https://www.factor10.com/&quot;&gt;factor10&lt;/a&gt;, we
automate several processes to reduce human error while ensuring flexibility for quick interventions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Controlled Script Updates&lt;/strong&gt;: During our build process, a utility fetches the latest versions of
third-party scripts, but changes are only introduced after a manual diff-check, giving us full
control over updates.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automated SRI Generation&lt;/strong&gt;: Hashes for all fetched scripts are automatically calculated and
embedded into the HTML, ensuring integrity.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automated Security Headers&lt;/strong&gt;: CSP rules are generated and applied to our NGINX configuration
during deployment. If any verification fails, the deployment is discarded, maintaining the
security of the live site.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;By automating these steps and pairing them with monitoring tools, we ensure consistent security
practices. Alerts notify our team of any deviations, allowing us to maintain control and respond
promptly.&lt;/p&gt;
&lt;h2&gt;Tools for Automating and Testing Security&lt;/h2&gt;
&lt;p&gt;The following tools can help you automate security practices and assess or improve your site&#39;s
security posture:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://csp-evaluator.withgoogle.com/&quot;&gt;Google’s CSP Evaluator&lt;/a&gt;: Analyzes your CSP and offers
suggestions for strengthening it.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://observatory.mozilla.org/&quot;&gt;Mozilla Observatory&lt;/a&gt;: Provides insights into security headers
and suggests improvements.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://securityheaders.com/&quot;&gt;securityheaders.com&lt;/a&gt;: Tests and rates your site&#39;s HTTP headers
based on best practices.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://playwright.dev/&quot;&gt;Playwright&lt;/a&gt;: A versatile tool for cross-browser testing to ensure
consistent security behavior.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://webperf.se/&quot;&gt;Webperf.se&lt;/a&gt;: Offers an
&lt;a href=&quot;https://github.com/Webperf-se/webperf_core&quot;&gt;open-source suite&lt;/a&gt; for analyzing performance,
accessibility, and security.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For our &lt;a href=&quot;https://factor10.com/websites/&quot;&gt;sustainable-websites&lt;/a&gt;, we use
&lt;a href=&quot;https://webperf.se/erbjudande/&quot;&gt;webperf&#39;s premium service&lt;/a&gt; for daily tests, alongside automated
alerts via &lt;a href=&quot;https://webperf.se/articles/webhooks/&quot;&gt;webhooks&lt;/a&gt; on Slack to notify us of any issues.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;While static websites are simpler than dynamic ones, they are not immune to modern supply chain
threats. The &lt;a href=&quot;http://polyfill.io/&quot;&gt;Polyfill.io&lt;/a&gt; incident serves as a reminder that even static sites can be compromised by
third-party dependencies. Implementing security measures like Subresource Integrity (SRI) and
Content Security Policy (CSP), combined with automation, significantly reduces your site&#39;s exposure
to supply chain risks.&lt;/p&gt;
&lt;p&gt;However, no defense strategy is complete without regular testing and monitoring. Vigilance, combined
with automation, ensures that your site remains resilient in the face of evolving threats without
sacrificing performance or efficiency.&lt;/p&gt;

    </content>
  </entry>
  <entry>
    <title>Optimizing GitHub Workflows for Efficiency and Sustainability</title>
    <link href="https://nizar.se/optimizing-github-workflows-for-efficiency-and-sustainability/"/>
    <updated>2024-06-12T00:00:00Z</updated>
    <id>https://nizar.se/optimizing-github-workflows-for-efficiency-and-sustainability/</id>
    <link rel="enclosure" type="image/jpeg" href="https://nizar.se/uploads/wind-turbine.jpg" />
    <content type="html">
      &lt;img src="https://nizar.se/uploads/wind-turbine.jpg" alt="Close-up of a modern wind turbine against a clear sky" /&gt;
      &lt;p&gt;Integrating automation into development workflows has become crucial in recent years. In this post,
I&#39;ll share a few strategies I&#39;ve found useful for making these workflows both more efficient and
sustainable. We&#39;ll look into strategies such as canceling redundant jobs, setting appropriate
workflow timeouts, optimizing caching techniques, and managing workflow triggers more effectively.&lt;/p&gt;
&lt;h2&gt;Cancel Redundant Jobs&lt;/h2&gt;
&lt;p&gt;When active development branches receive rapid updates, whether through direct pushes or pull
requests, they often trigger multiple instances of the same workflow. This redundancy can lead to
unnecessary resource consumption and potential delays in integration processes.&lt;/p&gt;
&lt;p&gt;One effective solution is to utilize
&lt;a href=&quot;https://docs.github.com/en/enterprise-cloud@latest/actions/using-jobs/using-concurrency#using-concurrency-in-different-scenarios&quot;&gt;concurrency groups&lt;/a&gt;.
By assigning a concurrency key, you can group workflows, thereby controlling their execution more
effectively. GitHub ensures that within a concurrency group, only one job or workflow runs at a
time, limiting it to one running and one pending job. Any new jobs that are triggered at that point
will instead be queued.&lt;/p&gt;
&lt;p&gt;However, by setting &lt;code&gt;cancel-in-progress&lt;/code&gt; to true, we cancel any ongoing workflows within the same
concurrency group when a new one is triggered. This approach effectively clears the queue and
ensures that any running workflows are processing the latest changes:&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token key atrule&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token key atrule&quot;&gt;branches&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; main&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token key atrule&quot;&gt;concurrency&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token key atrule&quot;&gt;group&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; integration&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;tests&lt;br /&gt;  &lt;span class=&quot;token key atrule&quot;&gt;cancel-in-progress&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;true&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For more granular control, particularly useful in environments that utilize branching strategies,
consider using dynamic expressions in the group naming. This configuration allows workflows
triggered on different branches to be grouped separately, ensuring that updates on one branch do not
interfere with the progress of workflows on another:&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;concurrency&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token key atrule&quot;&gt;group&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; integration&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;tests&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;$&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; github.ref &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token key atrule&quot;&gt;cancel-in-progress&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;true&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Employing this strategy optimizes the use of CI resources by avoiding redundant or outdated jobs
while maintaining the integrity of our codebase across all types of updates.&lt;/p&gt;
&lt;h2&gt;Set Workflow Timeouts&lt;/h2&gt;
&lt;p&gt;The default workflow timeout is 6 hours, which is often excessive for processes that complete within
minutes. Setting a more appropriate duration prevents wasteful use of resources, especially in cases
where a process might hang due to issues like deadlocks, resource starvation, or software bugs. For
instance, a lint check that typically completes within two minutes might only need a 10-minute
timeout:&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token key atrule&quot;&gt;lint-checks&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token key atrule&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ubuntu&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;latest&lt;br /&gt;    &lt;span class=&quot;token key atrule&quot;&gt;timeout-minutes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This simple adjustment prevents resources from being idly consumed, allowing them to be used for
more critical tasks and thereby enhancing the sustainability of your workflows.&lt;/p&gt;
&lt;h2&gt;Utilize Caching for Efficiency&lt;/h2&gt;
&lt;h3&gt;Optimize Dependency Handling&lt;/h3&gt;
&lt;p&gt;Workflow runs often share the exact same dependencies, which must be downloaded each time. Efficient
caching can save both time and resources. I recommend using the
&lt;a href=&quot;https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#about-caching-workflow-dependencies&quot;&gt;setup actions&lt;/a&gt;
for setting up environments like Node.js with caching enabled:&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Setup Node.js&lt;br /&gt;  &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; actions/setup&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;node@v4&lt;br /&gt;  &lt;span class=&quot;token key atrule&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token key atrule&quot;&gt;node-version&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token key atrule&quot;&gt;cache&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;npm&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This configuration caches the &lt;code&gt;~/.npm&lt;/code&gt; directory, which stores tarballs and metadata rather than the
&lt;code&gt;node_modules&lt;/code&gt;, reducing size and enhancing reusability across different environments.&lt;/p&gt;
&lt;p&gt;Using &lt;code&gt;npm ci&lt;/code&gt; instead of &lt;code&gt;npm install&lt;/code&gt; further accelerates builds by installing exact versions from
the &lt;code&gt;package-lock.json&lt;/code&gt;, ensuring reproducible builds and eliminating dependency resolution delays.&lt;/p&gt;
&lt;h3&gt;Cache and Restore Build Assets&lt;/h3&gt;
&lt;p&gt;For assets that are resource-intensive to recreate and don&#39;t frequently change, consider using the
&lt;a href=&quot;https://github.com/actions/cache&quot;&gt;cache action&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token key atrule&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token key atrule&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ubuntu&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;latest&lt;br /&gt;    &lt;span class=&quot;token key atrule&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Cache Assets&lt;br /&gt;        &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; actions/cache@v4&lt;br /&gt;        &lt;span class=&quot;token key atrule&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token key atrule&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; assets&lt;br /&gt;          &lt;span class=&quot;token key atrule&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; assets&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;$&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; github.run_id &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token key atrule&quot;&gt;restore-keys&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token scalar string&quot;&gt;&lt;br /&gt;            assets-&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This configuration caches the &lt;code&gt;assets&lt;/code&gt; directory, restoring it at the start of each build. By
referencing the run ID in the cache key, each build attempt will initially seek its own unique
cache. If there isn’t an exact match, the &lt;code&gt;restore-keys&lt;/code&gt; option allows the build to use the most
recent cache starting with &lt;code&gt;assets-&lt;/code&gt;. This technique is particularly useful for processes like
generating responsive images, where restoring them from the cache can save significant time and
resources.&lt;/p&gt;
&lt;p&gt;Note: GitHub retains caches for 7 days after the last access. For infrequent workflows, a
storage-based solution might be more appropriate. Cache management, including invalidation, can be
handled through the repository&#39;s
&lt;a href=&quot;https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#deleting-cache-entries&quot;&gt;web interface&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Optimize Workflow Triggers&lt;/h2&gt;
&lt;p&gt;Efficiently using &lt;code&gt;paths&lt;/code&gt; and &lt;code&gt;paths-ignore&lt;/code&gt; to specify which files or directories should trigger
workflows can help focus resources on meaningful changes.&lt;/p&gt;
&lt;p&gt;For instance, to exclude documentation updates from triggering workflows:&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token key atrule&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token key atrule&quot;&gt;paths-ignore&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;docs/**&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This configuration prevents any change in the &lt;code&gt;docs&lt;/code&gt; directory from triggering the workflow,
conserving resources for non-code updates.&lt;/p&gt;
&lt;p&gt;To trigger workflows only for changes in front-end code (e.g., JavaScript files):&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token key atrule&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token key atrule&quot;&gt;paths&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;frontend/**.js&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This setting ensures that workflows are triggered only when &lt;code&gt;js&lt;/code&gt; files in the &lt;code&gt;frontend&lt;/code&gt; directory
are modified, ensuring relevant tasks like linting are executed only when necessary.&lt;/p&gt;
&lt;p&gt;For more advanced usage, refer to the official GitHub Actions documentation
&lt;a href=&quot;https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#onpushpull_requestpull_request_targetpathspaths-ignore&quot;&gt;here&lt;/a&gt;.
Feel free to also check out the &lt;a href=&quot;https://github.com/dorny/paths-filter&quot;&gt;paths-filter&lt;/a&gt; action which
offers more advanced features.&lt;/p&gt;
&lt;h2&gt;Leverage ARM Architecture for Efficiency&lt;/h2&gt;
&lt;p&gt;GitHub recently announced
&lt;a href=&quot;https://github.blog/2024-06-03-arm64-on-github-actions-powering-faster-more-efficient-build-systems/&quot;&gt;ARM-based runners&lt;/a&gt;
for GitHub Team and Enterprise Cloud plans, with plans to offer them for open-source projects before
the year&#39;s end.&lt;/p&gt;
&lt;p&gt;These runners provide improvements in speed and energy consumption due to their reduced instruction
set. They consume 30-40% less energy for some of the most widely deployed workflows and are 37%
cheaper than their x64 counterparts.&lt;/p&gt;
&lt;p&gt;However, not all workflows are ideal for ARM runners, especially those that depend on software or
libraries not yet optimized for ARM architecture, or that rely on x64-specific optimizations.
Testing and evaluating your workflows will help you identify any compatibility issues and measure
the potential benefits in terms of speed, cost, and energy consumption.&lt;/p&gt;
&lt;p&gt;To utilize these ARM runners in your workflows, you first need to create an ARM-based runner as
shown in &lt;a href=&quot;https://www.youtube.com/watch?v=cgI6SBP8pEM&quot;&gt;this video&lt;/a&gt; or documented
&lt;a href=&quot;https://docs.github.com/en/actions/using-github-hosted-runners/about-larger-runners/about-larger-runners&quot;&gt;here&lt;/a&gt;.
Once set up, you can specify the runner by its name in the &lt;code&gt;runs-on&lt;/code&gt; field in your GitHub Actions
workflow. For example:&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token key atrule&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token key atrule&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; my&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;org&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;arm&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;runner&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This configuration directs GitHub Actions to use the specified ARM-based runner, allowing you to
take advantage of the efficiency and cost savings offered by ARM architecture.&lt;/p&gt;
&lt;h2&gt;Estimate Workflow Energy Consumption&lt;/h2&gt;
&lt;p&gt;Determining which strategy consumes fewer resources can sometimes be challenging. Tools like the
&lt;a href=&quot;https://github.com/green-coding-solutions/eco-ci-energy-estimation&quot;&gt;eco-ci-energy-estimation&lt;/a&gt;
action allow us to get estimates and help us make informed decisions.&lt;/p&gt;
&lt;p&gt;For instance, to determine whether caching npm dependencies would reduce resource consumption, I ran
5 workflow runs with caching and 5 without. The result showed that caching npm dependencies reduced
overall energy consumption and time.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://nizar.se/uploads/workflow-energy-comparison-chart.gif&quot; alt=&quot;Energy comparison of using caching vs not using caching&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;
&lt;em&gt;Energy comparison of using caching vs not using caching&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The following example demonstrates how to integrate this measurement tool into a workflow. Call
&lt;code&gt;start-measurement&lt;/code&gt; before running the work to be measured, and &lt;code&gt;get-measurement&lt;/code&gt; and
&lt;code&gt;display-results&lt;/code&gt; after.&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Initialize Energy Estimation&lt;br /&gt;  &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; green&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;coding&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;solutions/eco&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;ci&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;energy&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;estimation@v3&lt;br /&gt;  &lt;span class=&quot;token key atrule&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token key atrule&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; start&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;measurement&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Tests measurement&lt;br /&gt;  &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; green&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;coding&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;solutions/eco&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;ci&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;energy&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;estimation@v3&lt;br /&gt;  &lt;span class=&quot;token key atrule&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token key atrule&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; get&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;measurement&lt;br /&gt;    &lt;span class=&quot;token key atrule&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Install&#39;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Show Energy Results&lt;br /&gt;  &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; green&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;coding&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;solutions/eco&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;ci&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;energy&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;estimation@v3&lt;br /&gt;  &lt;span class=&quot;token key atrule&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token key atrule&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; display&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;results&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Upon completion, the workflow produces a summary that looks like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://nizar.se/uploads/workflow-energy-estimation-summary.gif&quot; alt=&quot;Workflow summary showing measurement estimates&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;
&lt;em&gt;Workflow summary showing measurement estimates&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The action sends metrics data to &lt;a href=&quot;http://metrics.green-coding.io/&quot;&gt;metrics.green-coding.io&lt;/a&gt; by default, including energy values,
duration of measurements, CPU model, and details about your repository and commit. This data is used
to create a badge and a detailed display of your CI runs’ energy consumption, viewable
&lt;a href=&quot;https://metrics.green-coding.io/ci-index.html&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you prefer not to share this data, simply set &lt;code&gt;send-data&lt;/code&gt; to &lt;code&gt;false&lt;/code&gt; in the action’s
configuration.&lt;/p&gt;
&lt;h2&gt;More Ways to Optimize Workflows&lt;/h2&gt;
&lt;p&gt;With these simple tips, you can significantly reduce costs, save time, and better allocate
resources. For more tips, I highly recommend the presentation
&amp;quot;&lt;a href=&quot;https://www.youtube.com/watch?v=mYBkSg1dz2Y&quot;&gt;Things your Pipeline Should (Not) Do&lt;/a&gt;&amp;quot; by my
colleague Raniz, who inspired me to write this post.&lt;/p&gt;

    </content>
  </entry>
  <entry>
    <title>Robot Control with the Jetson Nano</title>
    <link href="https://nizar.se/robot-control-with-the-jetson-nano/"/>
    <updated>2024-04-02T00:00:00Z</updated>
    <id>https://nizar.se/robot-control-with-the-jetson-nano/</id>
    <link rel="enclosure" type="image/jpeg" href="https://nizar.se/uploads/jetarm-robot-side-view.jpg" />
    <content type="html">
      &lt;img src="https://nizar.se/uploads/jetarm-robot-side-view.jpg" alt="Side view of a robotic arm on a tracked mobile platform" /&gt;
      &lt;p&gt;Two years ago, I got to dive into a project at the intersection of machine learning and hardware -
right before ChatGPT became a household name and when terms like
&lt;a href=&quot;https://en.wikipedia.org/wiki/Overfitting&quot;&gt;overfitting&lt;/a&gt; puzzled me. Nonetheless, I was really
excited about it, especially because it involved both software and hardware, a combination I&#39;m quite
fond of.&lt;/p&gt;
&lt;p&gt;The project was part of the
&lt;a href=&quot;https://developer.nvidia.com/embedded/learn/jetson-ai-certification-programs&quot;&gt;Nvidia Jetson AI Certification program&lt;/a&gt;,
which challenges participants to demonstrate their machine learning skills using the
&lt;a href=&quot;https://developer.nvidia.com/embedded/jetson-nano-developer-kit&quot;&gt;Jetson Nano Developer kit&lt;/a&gt;.
Essentially, the kit is an embedded computer designed specifically to accelerate machine learning
applications. Though not required, I also had access to a
&lt;a href=&quot;https://www.waveshare.com/jetank-ai-kit.htm&quot;&gt;robot&lt;/a&gt;, which I was eager to use.&lt;/p&gt;
&lt;p&gt;I set a goal to train a model that would enable the robot&#39;s arm to be controlled via hand gestures.
The robot was equipped with a small camera on its front, perfectly positioned for this task.&lt;/p&gt;
&lt;h2&gt;Image Classification&lt;/h2&gt;
&lt;p&gt;I began with image classification, where the model is trained to identify and categorize images into
specific classes. My goal was to recognize four hand gestures:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Thumbs up&lt;/li&gt;
&lt;li&gt;Thumbs down&lt;/li&gt;
&lt;li&gt;Fingers spread&lt;/li&gt;
&lt;li&gt;Fingers together&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://nizar.se/uploads/classification-feed-demo.gif&quot; alt=&quot;Image classification demo of hand grip and gestures&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;p&gt;This allowed me to command the robot&#39;s arm and grip movement using these gestures. However, it was
somewhat hit-or-miss. The approach was basic, capable of only recognizing one gesture at a time,
which limited the ability to control the arm&#39;s elevation and grip simultaneously.&lt;/p&gt;
&lt;p&gt;Moreover, the control was binary; It lacked the nuance to specify degrees of movement or grip
tightness, posing a challenge for precise control.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://nizar.se/uploads/classification-grip-demo.gif&quot; alt=&quot;Demo of the robot control using image classification&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Image Regression&lt;/h2&gt;
&lt;p&gt;Moving forward, I explored image regression. Unlike classification, this method involved training
the model to pinpoint my hand&#39;s features in images, providing coordinates for my fingertips. The
challenge then became translating these coordinates into accurate robot movements.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://nizar.se/uploads/regression-feed-index.gif&quot; alt=&quot;Image regression demo of hand grip&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;p&gt;A significant hurdle was accounting for the camera&#39;s depth perception, essential for distinguishing
between fingertips being spread apart versus the hand moving closer to the camera.&lt;/p&gt;
&lt;p&gt;I experimented with measuring distances between various hand landmarks as proxies for depth
perception, such as the distance from the thumb&#39;s top and the wrist&#39;s bottom corner, or between the
tips of the index and pinky fingers. This approach, however, introduced additional complexity and
new challenges, such as adjusting for the hand tilting and panning.&lt;/p&gt;
&lt;p&gt;Ultimately, the model&#39;s error margins and the camera&#39;s limitations led me to simplify my approach. I
chose to track only the thumb and index finger while maintaining a constant distance from the
camera. This simpler model achieved more predictable results and easier control.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://nizar.se/uploads/regression-day-7.gif&quot; alt=&quot;Demo of the robot control using image regression&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;p&gt;While the project may seem straightforward, it was incredibly insightful, making the seemingly
complex field of machine learning feel much more attainable.&lt;/p&gt;
&lt;p&gt;Every so often, I reflect on this project and wonder if a simpler solution exists for accurately
considering distance. An intriguing possibility that comes to mind is the use of two cameras,
mirroring the binocular vision of humans, to facilitate a more straightforward approach to depth
perception. This idea excites me, and I&#39;m keen to explore it further, possibly revisiting the
project with a new perspective in the future.&lt;/p&gt;
&lt;p&gt;You can find the source code and assembly instruction on my GitHub
&lt;a href=&quot;https://github.com/nizos/jetarm&quot;&gt;repo&lt;/a&gt;. If you are curious about machine learning or robotics, I
encourage you to give it a look - who knows what you might discover?&lt;/p&gt;

    </content>
  </entry>
  <entry>
    <title>Striving for Performance and Design Harmony in Web Development</title>
    <link href="https://nizar.se/striving-for-performance-and-design-harmony-in-web-development/"/>
    <updated>2023-09-20T00:00:00Z</updated>
    <id>https://nizar.se/striving-for-performance-and-design-harmony-in-web-development/</id>
    <link rel="enclosure" type="image/jpeg" href="https://nizar.se/uploads/smartphone-showing-design-definition.jpg" />
    <content type="html">
      &lt;img src="https://nizar.se/uploads/smartphone-showing-design-definition.jpg" alt="Close-up of smartphone screen displaying the definition of &#39;design&#39;" /&gt;
      &lt;p&gt;In modern web development, a fine balance between performance and user-centric design is key. It
doesn&#39;t just enhance visitor retention; it deepens their interaction with the content. My recent
project provided me a deep dive into achieving this delicate balance. Here is a recount of my
experience and the insights that I&#39;ve gained.&lt;/p&gt;
&lt;h2&gt;The Task at Hand&lt;/h2&gt;
&lt;p&gt;The project involved transforming a site initially built using 11ty and Forestry CMS. The goal was
clear: transitioning to Cloudcannon and securing top-notch performance metrics across the board.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://nizar.se/uploads/webperf-report-for-factor10.gif&quot; alt=&quot;Website score on webperf&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt; &lt;em&gt;The website&#39;s final scores
for accessibility, speed, standards, privacy, and security. Securing it the top position of all
websites in Sweden measured by &lt;a href=&quot;https://webperf.se/toplist/&quot;&gt;webperf.se&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Crafting the Developer Experience&lt;/h2&gt;
&lt;p&gt;A well crafted website not only looks good but is also built upon pillars of performance,
accessibility, and best practices. Here, tools like &lt;a href=&quot;https://tailwindcss.com/&quot;&gt;Tailwind&lt;/a&gt; offer an
appealing promise of swift development. However, every tool has its caveats. In the case of
Tailwind, it produced CSS with
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties&quot;&gt;custom properties&lt;/a&gt;, a
feature that at that point was yet to be &lt;a href=&quot;https://drafts.csswg.org/css-variables/&quot;&gt;standardized&lt;/a&gt;.
Instead of letting this be a setback, I explored alternatives to establish an equally efficient and
issue-free developer environment.&lt;/p&gt;
&lt;h2&gt;Embracing Modular CSS&lt;/h2&gt;
&lt;p&gt;Let&#39;s dive a bit into the CSS. A modular CSS structure promises maintainability and scalability in
design, paving the way for rapid feature deployment and updates. It ensures that while each
component stands on its own, it is harmonious with overarching design. The structure we employed
embodies this principle:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;component-library/
├─ components/
│  └─ sample/
│     ├─ sample.bookshop.yml
│     ├─ sample.test.js
│     ├─ sample.scss
│     └─ sample.eleventy.liquid
└─ shared/
   └─ styles/
      ├─ global.scss
      └─ variables.scss
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But what makes this structure dynamic? Enter SCSS. A powerful extension of the traditional CSS, SCSS
bestows developers with features like variables and nested rules. While vanilla CSS has its merits,
SCSS allows for a more dynamic and fluid styling approach. Our build process uses tools like
&lt;a href=&quot;https://www.npmjs.com/package/sass&quot;&gt;Sass&lt;/a&gt; to consolidate and optimize SCSS files, ensuring seamless
style deployment. The journey from SCSS to optimized CSS follows these steps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Identify the SCSS files.&lt;/li&gt;
&lt;li&gt;Compile them into regular CSS.&lt;/li&gt;
&lt;li&gt;Optimize the resultant CSS.&lt;/li&gt;
&lt;li&gt;Store it for deployment.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Discovery&lt;/h3&gt;
&lt;p&gt;To begin the journey of styling optimization, we must first pinpoint where all the styles reside.
Utilizing &lt;a href=&quot;https://www.npmjs.com/package/fast-glob&quot;&gt;fast-glob&lt;/a&gt;, we efficiently traverse the file
system, seeking out the SCSS files. Imagine wanting to identify all &lt;code&gt;.scss&lt;/code&gt; and &lt;code&gt;.css&lt;/code&gt; files within
the &lt;code&gt;src&lt;/code&gt; directory. Here is how it would look:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; fg &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;fast-glob&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; entries &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;src/**/*.{css,scss}&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Compilation&lt;/h3&gt;
&lt;p&gt;Having identified our list of SCSS files, the next step is compilation. Conventionally, you&#39;d find a
&amp;quot;main&amp;quot; SCSS file that &lt;code&gt;@import&lt;/code&gt;s other SCSS files, setting up a clear hierarchy. Compiling this main
file processes all the imported files in the order of their appearance.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; sass &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;sass&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; output &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; sass&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;renderSync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;path/to/main.scss&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A more flexible alternative to the traditional method is dynamic compilation, as exemplified by the
Bookshop sass bundler:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; sassInput &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; entries&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@import &quot;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;file&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;\n&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; output &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; sass&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;renderSync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; sassInput &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we create an in-memory virtual SCSS file that imports every SCSS file detected. By compiling
it, we incorporate all unique component styles.&lt;/p&gt;
&lt;h3&gt;Post-Processing&lt;/h3&gt;
&lt;p&gt;Compilation, while crucial, is just one part of the equation. We must enhance and optimize the
compiled styles. This is where powerful tools like &lt;a href=&quot;https://www.npmjs.com/package/postcss&quot;&gt;PostCSS&lt;/a&gt;
and &lt;a href=&quot;https://www.npmjs.com/package/cssnano&quot;&gt;cssnano&lt;/a&gt; come into play.&lt;/p&gt;
&lt;p&gt;PostCSS is a tool that doesn&#39;t merely refine styles — it transforms them through its plugin-based
system, allowing developers to decide exactly which transformations they want to apply. The
&lt;a href=&quot;https://www.npmjs.com/package/autoprefixer&quot;&gt;Autoprefixer&lt;/a&gt; plugin is a prime example, appending
vendor prefixes based on &lt;a href=&quot;https://caniuse.com/&quot;&gt;Can I use&lt;/a&gt; data, ensuring consistent cross-browser
compatibility. While PostCSS transforms, cssnano tightens. It compresses, strips, and trims the CSS
into its leanest form.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; postcss &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;postcss&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cssnano &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;cssnano&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; autoprefixer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;autoprefixer&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; inputCSS &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;a { transition: transform 1s; }&#39;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Simple CSS for demonstration.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; processedCSS &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;postcss&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;autoprefixer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cssnano&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;inputCSS&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; finalCss &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; processedCSS&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;css&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Together, PostCSS and cssnano aim to make our CSS not only adaptable but also blazing fast.&lt;/p&gt;
&lt;h3&gt;Writing&lt;/h3&gt;
&lt;p&gt;Having navigated the maze of style optimization, our last step is simple: writing our refined and
optimized CSS to a file.&lt;/p&gt;
&lt;h2&gt;Render Time&lt;/h2&gt;
&lt;p&gt;Ensuring fast page rendering is crucial for a seamless user experience. To realize this, we must
permit the browser to begin rendering even as resources are still in the loading phase. The primary
challenge lies in eliminating layout shifts and avoiding any sudden visual disturbances. For optimal
performance, resource loading and deployment must be carefully managed, particularly given the
potential influence on the page during their loading phase.&lt;/p&gt;
&lt;h3&gt;Font display&lt;/h3&gt;
&lt;p&gt;While custom fonts can undeniably elevate a website&#39;s aesthetic appeal, they may impede rendering
speed. Yet, with the technique of font swapping, it&#39;s possible to strike a balance between
aesthetics and efficiency.&lt;/p&gt;
&lt;p&gt;By integrating font swapping in our CSS, the browser is directed to utilize a system or fallback
font while the page is still loading. This circumvents the scenario where users find themselves
gazing at an empty space. Once the custom font has been fully loaded, the browser subtly switches to
it, ensuring that the design&#39;s integrity remains uncompromised without any delay for the user. The
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display&quot;&gt;font-display&lt;/a&gt; descriptor
facilitates this:&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token property&quot;&gt;font-display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; swap&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Enhancing font loading further, preloading the font primes the browser early about its significance,
allowing for efficient downloading.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;preload&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/fonts/font.woff2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;font&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;font/woff2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;crossorigin&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above method achieves this without introducing any JavaScript to our site.&lt;/p&gt;
&lt;h2&gt;Critical CSS&lt;/h2&gt;
&lt;p&gt;The term &#39;above-the-fold&#39; originates from newspaper design, referring to the content immediately
visible when a page loads, without the need for scrolling. By prioritizing the delivery of the
critical CSS necessary for this portion, we ensure the user&#39;s first impression is swift and
seamless.&lt;/p&gt;
&lt;p&gt;We do this by inlining these critical styles directly into the HTML&#39;s &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;, and thereby allowing
the browser to immediately render the immediate content without having to wait for the entire
stylesheet to load. The npm package, &lt;a href=&quot;https://www.npmjs.com/package/critical&quot;&gt;critical&lt;/a&gt;, offers a
simplified solution:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; critical &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;critical&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;critical&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;generate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;inline&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Will inline the generated CSS into the HTML&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;dist/&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Your base directory&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;index.html&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Source HTML file to be processed&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1300&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Viewport width&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;900&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Viewport height&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;ignore&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Rules to ignore, e.g., font-face which can be hefty&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;atrule&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;@font-face&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above example, the &lt;code&gt;index.html&lt;/code&gt; file is analyzed to determine the styles needed for its
above-the-fold content, and are subsequently inlined.&lt;/p&gt;
&lt;p&gt;This strategy provides several benefits. It accelerates the initial content rendering, allowing
earlier user interaction, and side-steps render blocking delays.&lt;/p&gt;
&lt;h2&gt;Layout shifts&lt;/h2&gt;
&lt;p&gt;Responsive design has revolutionized how sites adjust across devices, but it&#39;s not without hurdles.
For instance, while strategies like asynchronous content loading shows a lot of &#39;promise&#39; — pun very
much intended — it can occasionally result in unexpected layout shifts. Such shifts disorient users,
leading to unintended clicks and detracting from a seamless browsing experience.&lt;/p&gt;
&lt;p&gt;A hands-on approach is to establish size constraints for elements that might adjust with incoming
content. As an example, if a font swap alters an element&#39;s dimensions, the application of
&lt;code&gt;min-height&lt;/code&gt; and &lt;code&gt;min-width&lt;/code&gt; becomes a vital safeguard. This strategy ensures that our content is
primed to adapt to any changes, be they CMS updates or device reconfigurations, whilst maintaining a
steadfast structure.&lt;/p&gt;
&lt;h2&gt;Responsive Images&lt;/h2&gt;
&lt;p&gt;As screen sizes become more diverse, the need for responsive image techniques grows. Choosing the
right image size not only boosts a website&#39;s visual appeal but also ensures optimal performance.
Here, the HTML attribute, &lt;code&gt;sizes&lt;/code&gt;, stands out.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;sizes&lt;/code&gt; attribute of the &lt;code&gt;picture&lt;/code&gt; element allows us to guide the browser on the image display
size for varying viewport conditions. By defining both upper and lower limits with this attribute,
we ensure the best-suited image variant gets loaded.&lt;/p&gt;
&lt;p&gt;For instance, with the &lt;code&gt;sizes&lt;/code&gt; attribute, we can dictate how the image adapts across different
device widths. Here is how it works:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;(min-width: 1280px) 426px, (min-width: 768px) and (max-width: 1280px) 33vw, (min-width: 640px) and&lt;br /&gt;(max-width: 768px) 50vw, (max-width: 640px) 100vw&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;For screens wider than 1280 pixels, the image will be displayed at a fixed width of 426 pixels.&lt;/li&gt;
&lt;li&gt;For screens between 768 and 1280 pixels, the image will take up 33% of the viewport width.&lt;/li&gt;
&lt;li&gt;On screens ranging from 640 to 768 pixels, the image will cover half the viewport width.&lt;/li&gt;
&lt;li&gt;For a screen width of 640 pixels or fewer, the image will span the entire viewport width.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Alongside the &lt;code&gt;sizes&lt;/code&gt; attribute, it&#39;s worth highlighting the value of &lt;code&gt;srcset&lt;/code&gt;. While we dictate
display conditions with &lt;code&gt;sizes&lt;/code&gt;, &lt;code&gt;srcset&lt;/code&gt; lists multiple image versions, letting the browser select
the optimal one based on device specifics.&lt;/p&gt;
&lt;p&gt;The result is crisp visuals across devices, faster page loads, saved energy, and reduced bandwidth
use.&lt;/p&gt;
&lt;h2&gt;Security&lt;/h2&gt;
&lt;p&gt;At first glance, embedding inline CSS directly into HTML appears to be a straightforward approach to
styling. Yet, this simplicity can be deceptive, as it opens up potential security vulnerabilities
and challenges, particularly when the CSS undergoes changes during development.&lt;/p&gt;
&lt;p&gt;To counter such vulnerabilities, modern browsers have incorporated a security feature called the
Content Security Policy (CSP) Header. This feature delineates where various content types, be it
scripts, styles, or images, can be sourced from, ensuring that only content from trusted sources
gets executed or rendered.&lt;/p&gt;
&lt;p&gt;The significance of CSP becomes even clearer when we consider threats like cross-site scripting.
This nefarious tactic allows attackers to inject code into web pages that unsuspecting users then
view. Not only can it jeopardize user data, but it can also transform reputable sites into hubs of
malicious activity. The CSP stands as a safeguard against these and other similar threats.&lt;/p&gt;
&lt;p&gt;Now, when one chooses to go the route of inlining CSS, a specific hash of the content needs to be
added to the CSP header, signaling to the browser that this content is legitimate. But there is a
catch: should the styling undergo any alterations during development, which is often the case, the
associated hash needs a recalculation and subsequent update on the server. This step, often done
manually, is both labor-intensive and susceptible to errors.&lt;/p&gt;
&lt;p&gt;A possible workaround is the use of a nonce — a unique, one-time token. However, this method demands
a dynamic setting, such as a Node server. Given that our platform is tailored to serve only static
files, venturing into such complexities is unwarranted.&lt;/p&gt;
&lt;h2&gt;Automation&lt;/h2&gt;
&lt;p&gt;We can make this process smoother and hands-free by utilizing a Python script during deployment:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;First, we scan for HTML files: Store the deployment in a processing directory and sift through
it, identifying the HTML files.&lt;/li&gt;
&lt;li&gt;Detect Inline Styles: The script then parses the HTML files for inline styles.&lt;/li&gt;
&lt;li&gt;Hash Calculation: For each detected style, the script computes its hash.&lt;/li&gt;
&lt;li&gt;Config File Generation: Using a predefined template, the script produces a new configuration file
for the site. Within this file, a placeholder is replaced with the calculated &lt;code&gt;style-src&lt;/code&gt; hashes.&lt;/li&gt;
&lt;li&gt;Deployment and Validation: A critical step in the process. Before pushing any changes, the script
runs a series of tests and checks, validates the syntax and other parameters. Only when the
validation succeeds are the deployment files sent to their designated destination. Subsequently,
the configuration file is refreshed, and the server reloads it.&lt;/li&gt;
&lt;li&gt;Cleanup: If tests uncover issues or anomalies, all interim changes within the processing
directory are discarded without affecting the live website.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This allows us to safeguard our site&#39;s security while also eliminating manual intervention that can
be tedious and error-prone.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://nizar.se/uploads/factor10-headers-security-report-summary.gif&quot; alt=&quot;Headers security summary showing an A+ rating&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;
&lt;em&gt;Summary of the headers security analysis from &lt;a href=&quot;https://securityheaders.com/&quot;&gt;securityheaders.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Putting it all together&lt;/h2&gt;
&lt;p&gt;By harnessing these strategies, we create sites that excel both visually and functionally. In the
end, the elegance of a website isn&#39;t just in its visible design but also in its underlying
mechanics. As designers and developers, our goal is to master both fronts, crafting experiences that
are not only beautiful but are also performant, secure, and sustainable.&lt;/p&gt;
&lt;p&gt;With this, I would like to thank my colleagues at factor10 from whom I learn every day. I would also
like to thank my co-workers &lt;a href=&quot;https://www.linkedin.com/in/wengelin/&quot;&gt;Anders&lt;/a&gt; and
&lt;a href=&quot;https://www.linkedin.com/in/okkido/&quot;&gt;Peter&lt;/a&gt; who have worked alongside me for their excellent work.&lt;/p&gt;
&lt;p&gt;Feel free to check out the result for yourself: &lt;a href=&quot;https://factor10.com/&quot;&gt;factor10.com&lt;/a&gt;&lt;/p&gt;

    </content>
  </entry>
  <entry>
    <title>Improving Website Speed with Compression</title>
    <link href="https://nizar.se/improving-website-speed-with-compression/"/>
    <updated>2023-06-26T00:00:00Z</updated>
    <id>https://nizar.se/improving-website-speed-with-compression/</id>
    <link rel="enclosure" type="image/jpeg" href="https://nizar.se/uploads/numbers-on-a-screen.jpg" />
    <content type="html">
      &lt;img src="https://nizar.se/uploads/numbers-on-a-screen.jpg" alt="Close-up of numerical data on a screen" /&gt;
      &lt;p&gt;Google engineers, Arvind Jain and Jason Glasgow, stated that more than 99 human years are wasted
every day because of uncompressed content [&lt;a href=&quot;https://developers.googleblog.com/2009/11/use-compression-to-make-web-faster.html&quot; title=&quot;Use compression to make the web faster&quot;&gt;1&lt;/a&gt;]. That was in 2009. Advancements in technology have
since then brought improvements to internet speed, connectivity, and coverage. However, a lot has
also changed on the web and how we use it.&lt;/p&gt;
&lt;p&gt;Between 2012 and 2022, the average desktop page size increased from 803 KB to 2,284 KB. For mobile,
it increased from 386 KB to 2,010 KB. A staggering increase of 184% and 420% respectively in a
single decade [&lt;a href=&quot;https://www.keycdn.com/support/the-growth-of-web-page-size&quot; title=&quot;The Growth of Web Page Size&quot;&gt;2&lt;/a&gt;].&lt;/p&gt;
&lt;p&gt;During the same period, the number of internet users has also more than doubled, increasing from
roughly 2.2 to 5.3 billion internet users, an increase from roughly 35% to 66% of the world
population that use the internet [&lt;a href=&quot;https://www.itu.int/hub/publication/d-ind-ict_mdd-2022&quot; title=&quot;Measuring digital development: Facts and Figures 2022&quot;&gt;3&lt;/a&gt;].&lt;/p&gt;
&lt;p&gt;At the risk of preaching to the choir, the minute performance improvements we make to the websites
we create accumulate to astounding and far-reaching impacts. Their importance and significance can
not be understated, especially considering how simple some of them are. In this post, we&#39;ll explore
how to improve website speed by leveraging HTTP compression and pre-compressing files.&lt;/p&gt;
&lt;h2&gt;HTTP Compression&lt;/h2&gt;
&lt;p&gt;One technique that has significantly contributed to website speed improvement is HTTP compression.
This seamless capability in our web servers and browsers, which can easily go unnoticed, improves
transfer speed and bandwidth utilization by compressing HTTP data before sending it. The scheme used
for the compression is negotiated through the client advertising methods it supports.&lt;/p&gt;
&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;GET /encrypted-area HTTP/1.1&lt;br /&gt;Host: www.example.com&lt;br /&gt;Accept-Encoding: gzip, deflate&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The server can also support multiple compression schemes. In such a case, the server lists them in
the &lt;code&gt;Content-Encoding&lt;/code&gt; or &lt;code&gt;Transfer-Encoding&lt;/code&gt; field in the HTTP response.&lt;/p&gt;
&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;HTTP/1.1 200 OK&lt;br /&gt;Date: mon, 26 June 2016 22:38:34 GMT&lt;br /&gt;Server: Apache/1.3.3.7 (Unix)  (Red-Hat/Linux)&lt;br /&gt;Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT&lt;br /&gt;Accept-Ranges: bytes&lt;br /&gt;Content-Length: 438&lt;br /&gt;Connection: close&lt;br /&gt;Content-Type: text/html; charset=UTF-8&lt;br /&gt;Content-Encoding: gzip&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Compression Schemes&lt;/h2&gt;
&lt;p&gt;The two most common compression schemes used today are Gzip (&lt;code&gt;gzip&lt;/code&gt;) and Brotli (&lt;code&gt;br&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Gzip, the older of the two, was released in 1993 during the formative years of the internet. It was
created to compress files and has since been adapted to compress streams. Brotli on the other hand,
which was released in 2013 by Google, was designed from the ground up to compress streams making it
a preferred scheme for web.&lt;/p&gt;
&lt;p&gt;Both Gzip and Brotli combine variations of the &lt;a href=&quot;https://en.wikipedia.org/wiki/LZ77_and_LZ78&quot;&gt;LZ77&lt;/a&gt;
algorithm and &lt;a href=&quot;https://en.wikipedia.org/wiki/Huffman_coding&quot;&gt;Huffman coding&lt;/a&gt;, among others, to
provide lossless general-purpose compression.&lt;/p&gt;
&lt;p&gt;LZ77 replaces repeated occurrences of data with references to a single copy of it using an encoded
length-distance pair. This match effectively states that the length following characters are
identical to the characters distance before them. This algorithm formed the basis of compression
schemes such as GIF and the deflate algorithm used in PNG and ZIP.&lt;/p&gt;
&lt;p&gt;The Huffman coding algorithm further compresses the data by using a dictionary of recurring
characters and their frequency. Characters, and groups of which, are replaced by variable-length
codes based on their occurrence with more frequent ones being assigned shorter codes.&lt;/p&gt;
&lt;p&gt;Brotli is further able to reach higher compression density by utilizing context models and other
improvements. It also uses a pre-defined dictionary along its dynamic memory, roughly 120 KiB
containing 13,000 common words, phrases and substrings derived from internet documents.&lt;/p&gt;
&lt;p&gt;This allows Brotli to reach compression densities that are roughly 15% denser for JavaScript and CSS
files, and 20% denser for HTML files compared to Gzip. That said, Brotli can also take longer to
compress data compared to Gzip. The higher the level of compression, the longer it takes.&lt;/p&gt;
&lt;h2&gt;Pre-Compressing Files&lt;/h2&gt;
&lt;p&gt;While compression significantly reduces the size of transmitted data, it also happens at run time
and as such impedes performance due to the required processing overhead. Luckily, we can utilize
modules that allow us to serve pre-compressed files, effectively eliminating all the processing
overhead at runtime. This is ideal for serving static content and static files.&lt;/p&gt;
&lt;p&gt;We will have to first compress our files. The &lt;code&gt;node:zlib&lt;/code&gt; module provides all the compression
functionality needed to do so using Gzip and Brotli. The documentation provides an example of how to
accomplish this by piping the source stream (file) through a &lt;code&gt;zlib&lt;/code&gt; Transform into a destination
stream.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; createGzip &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;node:zlib&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; pipeline &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;node:stream&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; createReadStream&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; createWriteStream &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;node:fs&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; gzip &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createGzip&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; source &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createReadStream&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;input.txt&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; destination &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createWriteStream&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;input.txt.gz&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;pipeline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;source&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; gzip&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; destination&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;An error occurred:&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; err&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exitCode &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For Brotli, we simply replace the Gzip object with a &lt;code&gt;BrotliCompress&lt;/code&gt; object. We can call
&lt;code&gt;createBrotliCompress()&lt;/code&gt; instead of &lt;code&gt;createGzip()&lt;/code&gt; to create our transform stream. Additionally, we
can pass an &lt;code&gt;options&lt;/code&gt; object to specify the compression level and fine-tune other parameters to our
liking.&lt;/p&gt;
&lt;p&gt;We then simply create the necessary functionality to recursively iterate through the files in our
build directory and create &lt;code&gt;.gz&lt;/code&gt; and &lt;code&gt;.br&lt;/code&gt; compressed files next to the uncompressed files. Finally,
we add the command to our build script and have it automatically execute as a final build step.&lt;/p&gt;
&lt;h2&gt;Serving Pre-Compressed Files&lt;/h2&gt;
&lt;p&gt;For NGINX, we can use
&lt;a href=&quot;https://nginx.org/en/docs/http/ngx_http_gzip_static_module.html#gzip_static&quot;&gt;ngx_http_gzip_static_module&lt;/a&gt;
for Gzip and &lt;a href=&quot;https://github.com/google/ngx_brotli#brotli_static&quot;&gt;ngx_brotli&lt;/a&gt; for Brotli
precompressed files. These allow us to precompress our files and have them served as such.&lt;/p&gt;
&lt;p&gt;Nginx uses a nifty tool called &lt;a href=&quot;https://hg.nginx.org/pkg-oss/&quot;&gt;pkg-oss&lt;/a&gt; to create the dynamic module
packages for their official repositories. It contains a script that automates the process, which we
can use to create installable packages with the correct dependencies for our modules.&lt;/p&gt;
&lt;p&gt;This method ensures that the dependency between our modules and NGINX is honored, facilitating
seamless upgrades and avoiding upgrade failures. The code block below shows how we can use it to
create &lt;code&gt;deb&lt;/code&gt; packages for our &lt;code&gt;ngx_brotli&lt;/code&gt; module. You can use &lt;code&gt;curl&lt;/code&gt; or any other similar tool
instead of &lt;code&gt;wget&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;wget https://hg.nginx.org/pkg-oss/raw-file/default/build_module.sh&lt;br /&gt;chmod a+x build_module.sh&lt;br /&gt;./build_module.sh -v 1.23.3 --force-dynamic https://github.com/google/ngx_brotli.git&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Do note however that this should be done in a separate build environment to ensure that only
operation-necessary software is installed on the production server. Further, this script might not
work for every module and the installable packages created by it are not intended for distribution.
Finally, seamless upgrades require a &lt;code&gt;yum&lt;/code&gt; or &lt;code&gt;apt&lt;/code&gt; repository. For instructions and more
information, check out Liam Crillys article
&lt;a href=&quot;https://www.nginx.com/blog/creating-installable-packages-dynamic-modules/&quot;&gt;Creating Installable Packages for Dynamic Modules&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Upon completion, the script outputs the path of the created &lt;code&gt;deb&lt;/code&gt; packages which we can install with
the help of &lt;code&gt;dpkg&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;dpkg &lt;span class=&quot;token parameter variable&quot;&gt;-i&lt;/span&gt; nginx-module-brotli_1.23.3+1.0-1~jammy_amd64.deb&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We then need to configure NGINX to use the newly installed module. We do this by editing the main
configuration file.&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;nano&lt;/span&gt; /etc/nginx/nginx.conf&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We simply add the directive we are interested in to the http block. For example:&lt;/p&gt;
&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;brotli on;&lt;br /&gt;brotli_comp_level 6;&lt;br /&gt;brotli_static on;&lt;br /&gt;brotli_types application/atom+xml application/javascript&lt;br /&gt;  application/json application/rss+xml application/vnd.ms-fontobject&lt;br /&gt;  application/x-font-opentype application/x-font-truetype&lt;br /&gt;  application/x-font-ttf application/x-javascript&lt;br /&gt;  application/xhtml+xml application/xml font/eot font/opentype&lt;br /&gt;  font/otf font/truetype image/svg+xml image/vnd.microsoft.icon&lt;br /&gt;  image/x-icon image/x-win-bitmap text/css text/javascript&lt;br /&gt;  text/plain text/xml;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;brotli&lt;/code&gt;: Enables on-the-fly compression of responses.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;brotli_comp_level&lt;/code&gt;: Sets the on-the-fly compression levels. Range is 0 - 11, default is 6.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;brotli_static&lt;/code&gt;: Enables checking for pre-compressed files with .br extension.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;brotli_types&lt;/code&gt;: MIME types to enable on-the-fly compression for.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Check the official &lt;a href=&quot;https://github.com/google/ngx_brotli&quot;&gt;ngx_brotli&lt;/a&gt; repo for additional
information and configuration.&lt;/p&gt;
&lt;p&gt;Check for any syntax errors after saving with the following command:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;nginx &lt;span class=&quot;token parameter variable&quot;&gt;-t&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The output should look something like this:&lt;/p&gt;
&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;nginx: the configuration file /etc/nginx/nginx.conf syntax is ok&lt;br /&gt;nginx: configuration file /etc/nginx/nginx.conf test is successful&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, restart NGINX to apply the changes.&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;systemctl restart nginx&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;NGINX is now configured with Brotli support. You can verify this by running the following command:&lt;/p&gt;
&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;curl -H ‘Accept-Encoding: br’ -I https://your-website.com&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The result should contain the following line:&lt;/p&gt;
&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;content-encoding: br&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Be also sure to test your improved website speed by using PageSpeed Insights, Lighthouse or any
other tool you prefer. Your numbers may vary depending on several factors such as existing
bottlenecks, but you should see an improvement.&lt;/p&gt;
&lt;h2&gt;Results&lt;/h2&gt;
&lt;p&gt;After compressing and serving static files, the loading speed of my website improved significantly.
However, don&#39;t just take my word for it. Let&#39;s examine some real-world examples that illustrate the
effectiveness of compression.&lt;/p&gt;
&lt;p&gt;Here is how the time-to-interactive changed on mobile for the following sites:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Organization website: Reduced from 1.5 to 0.9 seconds.&lt;/li&gt;
&lt;li&gt;Conference website: Reduced from 1.4 to 1.0 seconds.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are just a few examples of how powerful compression can be in improving website speed. With
the easy implementation and significant benefits, it is clear why HTTP compression and
pre-compressing files have become standard practice in web development.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Compression plays a vital role in the modern web. It helps us deliver content faster to users while
preserving network resources. With technologies like Gzip and Brotli, we can make websites more
efficient without compromising the quality of the data. As the internet continues to grow and
evolve, we can only expect compression techniques to become even more critical. In future posts,
we&#39;ll explore more ways to improve website performance and make the most of available resources.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://developers.googleblog.com/2009/11/use-compression-to-make-web-faster.html&quot;&gt;https://developers.googleblog.com/2009/11/use-compression-to-make-web-faster.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.keycdn.com/support/the-growth-of-web-page-size&quot;&gt;https://www.keycdn.com/support/the-growth-of-web-page-size&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.itu.int/hub/publication/d-ind-ict_mdd-2022&quot;&gt;https://www.itu.int/hub/publication/d-ind-ict_mdd-2022&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

    </content>
  </entry>
  <entry>
    <title>Serving Sites with NGINX QUIC</title>
    <link href="https://nizar.se/serving-sites-with-nginx-quic/"/>
    <updated>2023-02-28T00:00:00Z</updated>
    <id>https://nizar.se/serving-sites-with-nginx-quic/</id>
    <link rel="enclosure" type="image/jpeg" href="https://nizar.se/uploads/internet-and-usb-cables.jpg" />
    <content type="html">
      &lt;img src="https://nizar.se/uploads/internet-and-usb-cables.jpg" alt="Close-up of USB and Ethernet cable on a white surface" /&gt;
      &lt;p&gt;NGINX has
&lt;a href=&quot;https://www.nginx.com/blog/binary-packages-for-preview-nginx-quic-http3-implementation/&quot;&gt;recently released&lt;/a&gt;
prebuilt &lt;a href=&quot;https://quic.nginx.org/packages.html&quot;&gt;binary packages&lt;/a&gt; for the preview NGINX QUIC+HTTP/3
implementation for Red Hat Enterprise Linux 9 and Ubuntu 22.04.&lt;/p&gt;
&lt;p&gt;The prebuilt binary packages eliminate the need to compile from source and automatically install a
&lt;a href=&quot;https://github.com/quictls&quot;&gt;quicktls&lt;/a&gt; library package as a dependency as OpenSSL does not yet
support QUIC.&lt;/p&gt;
&lt;h2&gt;QUIC&lt;/h2&gt;
&lt;p&gt;QUIC is a general-purpose transport layer network protocol that provides built-in security and
improved performance compared to TCP + TLS. Its built-in security features, such as encryption and
authentication, allow for the exchange of setup keys and protocols to take place in the initial
handshake. Thus reducing the connection setup overhead and latency as shown by the diagram below.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://nizar.se/uploads/quic-handshake-comparison.gif&quot; alt=&quot;QUIC diagram&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;p&gt;For a more detailed breakdown of QUIC and how it works, checkout Cloudflare&#39;s blog article
&lt;a href=&quot;https://blog.cloudflare.com/the-road-to-quic/&quot;&gt;The Road to QUIC&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Using NGINX QUIC&lt;/h2&gt;
&lt;p&gt;What follows is a step-by-step guide on how to serve a website using NGINX QUIC. For this setup, we
will use a newly created Ubuntu 22.04 server.&lt;/p&gt;
&lt;h3&gt;Update the system&lt;/h3&gt;
&lt;p&gt;We start by ensuring that the system is up-to-date as usual.&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Install the latest updates&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt&lt;/span&gt; update &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt&lt;/span&gt; upgrade &lt;span class=&quot;token parameter variable&quot;&gt;-y&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# Reboot if necessary&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;reboot&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-h&lt;/span&gt; now&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Install NGINX-QUIC&lt;/h3&gt;
&lt;p&gt;We then set up the repository and install the pre-built packages.&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Install the prerequisites&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt&lt;/span&gt; update &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; gnupg2 ca-certificates lsb-release ubuntu-keyring&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# Import an official nginx signing key to verify packages authenticity&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; https://nginx.org/keys/nginx_signing.key &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; gpg &lt;span class=&quot;token parameter variable&quot;&gt;--dearmor&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;tee&lt;/span&gt; /usr/share/keyrings/nginx-archive-keyring.gpg &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;/dev/null&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# Set up the apt repository for nginx-quic packages&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \&lt;br /&gt;https://packages.nginx.org/nginx-quic/ubuntu &lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;`&lt;/span&gt;lsb_release &lt;span class=&quot;token parameter variable&quot;&gt;-cs&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;`&lt;/span&gt;&lt;/span&gt; nginx-quic&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;tee&lt;/span&gt; /etc/apt/sources.list.d/nginx-quic.list&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# Install nginx-quic&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt&lt;/span&gt; update&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; nginx-quic&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Firewall&lt;/h3&gt;
&lt;p&gt;Enable the firewall if it is not already enabled and make sure to allow UDP traffic through
port 443. UDP uses a connectionless communication model, it is a fire and forget protocol. It is
what makes the reduction of overhead possible.&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Adjust firewall&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; ufw default allow outgoing&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; ufw default deny incoming&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; ufw allow &lt;span class=&quot;token function&quot;&gt;ssh&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; ufw allow &lt;span class=&quot;token number&quot;&gt;80&lt;/span&gt;/tcp&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; ufw allow &lt;span class=&quot;token number&quot;&gt;443&lt;/span&gt;/tcp&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; ufw allow &lt;span class=&quot;token number&quot;&gt;443&lt;/span&gt;/udp&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# Enable firewall&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; ufw &lt;span class=&quot;token builtin class-name&quot;&gt;enable&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Certbot&lt;/h3&gt;
&lt;p&gt;Install certbot, or your favorite tool to issue and renew certificates. A lit of alternative clients
can be found &lt;a href=&quot;https://letsencrypt.org/docs/client-options/&quot;&gt;here&lt;/a&gt;. We will use snap to since it is
the method recommended by Certbot. You can find alternative installation methods
&lt;a href=&quot;https://eff-certbot.readthedocs.io/en/stable/install.html&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Make sure snapd core is up to date&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; snap &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; core&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; snap refresh core&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# Ensure that no older version is already installed&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt&lt;/span&gt; remove certbot&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# Install the certbot package&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; snap &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--classic&lt;/span&gt; certbot&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# Link the certbot command from the snap install directory&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ln&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; /snap/bin/certbot /usr/bin/certbot&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Site directory&lt;/h3&gt;
&lt;p&gt;We will now create a directory to store our site and its data. This is where the server will look
for the site&#39;s contents when serving out visitors. You can choose a different location that the one
I chose, just make sure to make the same adjustment in the other places that this path appears in as
you follow along.&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-p&lt;/span&gt; /var/www/WEBSITE/html/&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;chown&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-R&lt;/span&gt; www-data:www-data /var/www/WEBSITE/html/&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;chmod&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-R&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;755&lt;/span&gt; /var/www/WEBSITE&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Webpage&lt;/h3&gt;
&lt;p&gt;With our directory created, we will now create a simple html page for the purpose of demonstrating
the functionality. This can be replaced with your actual site contents when we are done.&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Create a sample index.html&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;nano&lt;/span&gt; /var/www/WEBSITE/html/index.html&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Paste in the following snippet and save.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;head&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Welcome to WEBSITE!&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;head&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Success! The WEBSITE server block is working!&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Configure NGINX&lt;/h3&gt;
&lt;p&gt;It is now time to make some adjustments to our NGINX configuration.&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;nano&lt;/span&gt; /etc/nginx/nginx.conf&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Adjust the config file to match the following block, which is enough to get us started for now.&lt;/p&gt;
&lt;pre class=&quot;language-txt&quot;&gt;&lt;code class=&quot;language-txt&quot;&gt;&lt;br /&gt;user  www-data;&lt;br /&gt;worker_processes  auto;&lt;br /&gt;&lt;br /&gt;error_log  /var/log/nginx/error.log notice;&lt;br /&gt;pid        /var/run/nginx.pid;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;events {&lt;br /&gt;    worker_connections  1024;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;http {&lt;br /&gt;    include       /etc/nginx/mime.types;&lt;br /&gt;    default_type  application/octet-stream;&lt;br /&gt;&lt;br /&gt;    log_format  main  &#39;$remote_addr - $remote_user [$time_local] &quot;$request&quot; &#39;&lt;br /&gt;                      &#39;$status $body_bytes_sent &quot;$http_referer&quot; &#39;&lt;br /&gt;                      &#39;&quot;$http_user_agent&quot; &quot;$http_x_forwarded_for&quot;&#39;;&lt;br /&gt;&lt;br /&gt;    access_log  /var/log/nginx/access.log  main;&lt;br /&gt;&lt;br /&gt;    sendfile  on;&lt;br /&gt;    keepalive_timeout  65;&lt;br /&gt;    gzip  on;&lt;br /&gt;&lt;br /&gt;    include /etc/nginx/conf.d/*.conf;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What follows is a brief explanation of what the different directives and values do.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;user&lt;/code&gt; defines the user used by the worker processes.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;worker-processes&lt;/code&gt; the number of worker processes. Setting it to the number of CPU cores is a good
start, &lt;code&gt;auto&lt;/code&gt; automatically detects it for us.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;error_log&lt;/code&gt; defines a log file to store logs and the level of logging.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pid&lt;/code&gt; defines a file that will store the process ID of the main process.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;events&lt;/code&gt; configuration of connection processing.
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;worker_connections&lt;/code&gt; sets the maximum number of simultaneous connections that can be opened by a
worker process.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;the top-level &lt;code&gt;http&lt;/code&gt; block.
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;include /etc/nginx/mime.types&lt;/code&gt; tells browsers how to handle different file formats.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;default_type application/octet-stream;&lt;/code&gt; tells browsers to treat files not identified in
&lt;code&gt;/etc/nginx/mime.types&lt;/code&gt; as downloadable binaries.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;log_format&lt;/code&gt; specifies the log format.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;access_log&lt;/code&gt; sets the path and format for logging.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;send_file&lt;/code&gt; ensures that nginx operations will not block disk I/O.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;keepalive_timeout&lt;/code&gt; the duration to keep worker_connections open for each client.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gzip&lt;/code&gt; compress data to browsers to enhance performance.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;include /etc/nginx/conf.d/*.conf;&lt;/code&gt; include all configuration files in provided directory.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Create the website configuration&lt;/h3&gt;
&lt;p&gt;We will now create a configuration file for the website in the /etc/nginx/conf.d/ directory inline
with the new conventions which you can read more about
&lt;a href=&quot;https://www.oreilly.com/library/view/nginx-cookbook/9781492049098/ch01.html&quot;&gt;here&lt;/a&gt;. All .conf files
placed in this directory are included in the top-level http block.&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;nano&lt;/span&gt; /etc/nginx/conf.d/WEBSITE.conf&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Paste in the following content and save the file.&lt;/p&gt;
&lt;pre class=&quot;language-txt&quot;&gt;&lt;code class=&quot;language-txt&quot;&gt;server {&lt;br /&gt;    listen 80;&lt;br /&gt;    server_name WEBSITE www.WEBSITE;&lt;br /&gt;&lt;br /&gt;    root /var/www/WEBSITE/html;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What follows is a brief explanation of what the different directives and values do.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;server&lt;/code&gt; defines a new server block for nginx to listen to.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;listen 80&lt;/code&gt; the port nginx will listen on.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;server_name&lt;/code&gt; the hostnames of the requests which should be directed to this server.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;root&lt;/code&gt; tells nginx where to look for content.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Start NGINX&lt;/h3&gt;
&lt;p&gt;It&#39;s time to apply the changes and start NGINX.&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Start and enable nginx on system startup if not already enabled&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; systemctl start nginx&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; systemctl &lt;span class=&quot;token builtin class-name&quot;&gt;enable&lt;/span&gt; nginx&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# Check the status of nginx&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; systemctl status nginx&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# Make sure no errors were encountered&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; nginx &lt;span class=&quot;token parameter variable&quot;&gt;-t&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Makes sure that no errors were encountered. The last command should display helpful information to
help you troubleshoot any failed validations.&lt;/p&gt;
&lt;h3&gt;Generate certificates&lt;/h3&gt;
&lt;p&gt;With NGINX up and running, it is time to generate our certificates. We do this with the help of
certbot. When prompted, fill in your email address and agree to the terms.&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; certbot &lt;span class=&quot;token parameter variable&quot;&gt;--nginx&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-d&lt;/span&gt; WEBSITE &lt;span class=&quot;token parameter variable&quot;&gt;-d&lt;/span&gt; www.WEBSITE&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Those certificates are valid for 90 days. Certbot adds a systemd timer that checks our certs for us
twice a day and renews any certs that will expire within 30 days.&lt;/p&gt;
&lt;p&gt;We can verify the status of the timer by running the following command.&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; systemctl status snap.certbot.renew.service&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can also test the renewal process by running the following command.&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; certbot renew --dry-run&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&#39;s Encrypt will also send you a warning email to the email account you provided when creating the
certificates if the renewal process fails.&lt;/p&gt;
&lt;h3&gt;Enable QUIC&lt;/h3&gt;
&lt;p&gt;Certbot should now have generated the certificates for us and updated our site&#39;s configuration file
accordingly. We need to make some final adjustments to enable QUIC.&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;nano&lt;/span&gt; /etc/nginx/conf.d/WEBSITE.conf&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Adjust the file&#39;s contents to match the following block.&lt;/p&gt;
&lt;pre class=&quot;language-txt&quot;&gt;&lt;code class=&quot;language-txt&quot;&gt;server {&lt;br /&gt;    # Using the same port number for QUIC and TCP&lt;br /&gt;    listen 443 http3 reuseport;       # IPv4 QUIC&lt;br /&gt;    listen 443 ssl http2;             # IPv4 TCP&lt;br /&gt;    listen [::]:443 http3 reuseport;  # IPv6 QUIC&lt;br /&gt;    listen [::]:443 ssl http2;        # IPv6 TCP&lt;br /&gt;&lt;br /&gt;    # Server name&lt;br /&gt;    server_name WEBSITE www.WEBSITE;&lt;br /&gt;&lt;br /&gt;    # Site root&lt;br /&gt;    root /var/www/WEBSITE/html;&lt;br /&gt;&lt;br /&gt;    # Certificates&lt;br /&gt;    ssl_certificate /etc/letsencrypt/live/WEBSITE/fullchain.pem; # managed by Certbot&lt;br /&gt;    ssl_certificate_key /etc/letsencrypt/live/WEBSITE/privkey.pem; # managed by Certbot&lt;br /&gt;    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot&lt;br /&gt;    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot&lt;br /&gt;}&lt;br /&gt;server {&lt;br /&gt;    if ($host = www.WEBSITE) {&lt;br /&gt;        return 301 https://$host$request_uri;&lt;br /&gt;    } # managed by Certbot&lt;br /&gt;&lt;br /&gt;    if ($host = WEBSITE) {&lt;br /&gt;        return 301 https://$host$request_uri;&lt;br /&gt;    } # managed by Certbot&lt;br /&gt;&lt;br /&gt;    listen 80;&lt;br /&gt;    server_name WEBSITE www.WEBSITE;&lt;br /&gt;    return 404; # managed by Certbot&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we added &lt;code&gt;listen [::]&lt;/code&gt; so that nginx listens to IPv6 connections. You can remove this
directive if you have not enabled IPv6 for your domain. We have also configured &lt;code&gt;HTTP/2&lt;/code&gt; to be the
starting http version for new connections instead of &lt;code&gt;HTTP/1.1&lt;/code&gt; for better performance. Connections
will switch to QUIC after it is discovered. The second server block is used to redirect unencrypted
traffic to encrypted traffic.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Update&lt;/em&gt;: The configuration has changed. Use &lt;code&gt;quic&lt;/code&gt; and &lt;code&gt;ssl&lt;/code&gt; separately in &lt;code&gt;listen&lt;/code&gt; directives and
enable &lt;code&gt;http2&lt;/code&gt; globally with &lt;code&gt;http2 on;&lt;/code&gt;. Additionally, new
&lt;a href=&quot;https://nginx.org/en/docs/quic.html&quot;&gt;QUIC-related settings&lt;/a&gt; have been added:&lt;/p&gt;
&lt;pre class=&quot;language-txt&quot;&gt;&lt;code class=&quot;language-txt&quot;&gt;    # Using the same port number for QUIC and TCP&lt;br /&gt;    listen 443 quic reuseport;&lt;br /&gt;    listen 443 ssl;&lt;br /&gt;    listen [::]:443 quic;&lt;br /&gt;    listen [::]:443 ssl;&lt;br /&gt;    http2 on;&lt;br /&gt;&lt;br /&gt;    # QUIC&lt;br /&gt;    quic_retry on;&lt;br /&gt;    ssl_early_data on;&lt;br /&gt;    quic_gso on;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Apply changes&lt;/h3&gt;
&lt;p&gt;It is time to apply the new changes after checking that everything is fine.&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Make sure no errors were encountered&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; nginx &lt;span class=&quot;token parameter variable&quot;&gt;-t&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# Restart NGINX&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; systemctl reload nginx&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Live!&lt;/h3&gt;
&lt;p&gt;The website should now be live with QUIC+HTTP/3 enabled.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://nizar.se/uploads/configuring-quic-browser-result.gif&quot; alt=&quot;View of website in browser&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Verify&lt;/h3&gt;
&lt;p&gt;Head over to &lt;a href=&quot;https://www.http3check.net/&quot;&gt;https://www.http3check.net/&lt;/a&gt; to verify that QUIC and
HTTP/3 are supported on your site.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://nizar.se/uploads/quic-support-verification.gif&quot; alt=&quot;QUIC verification&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Concluding Remarks&lt;/h2&gt;
&lt;p&gt;With this &lt;em&gt;quic&lt;/em&gt; demonstration completed, there are some things to consider before using it. Given
that internet service has gotten more reliable over the years, the likelihood of issues caused by
dropped packages has become increasingly unlikely. At the same time, the amount of bandwidth saved
makes it an attractive tradeoff especially on the server side. This is also a preview release. That
said, there are several production deployments according to &lt;a href=&quot;https://quic.nginx.org/&quot;&gt;NGINX&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I will also cover topics such as optimising NGINX for performance and strengthening security through
the use of headers in future posts.&lt;/p&gt;

    </content>
  </entry>
  <entry>
    <title>Look Smarter With Git: Rewriting Your History</title>
    <link href="https://nizar.se/look-smarter-with-git-rewriting-your-history/"/>
    <updated>2022-08-08T00:00:00Z</updated>
    <id>https://nizar.se/look-smarter-with-git-rewriting-your-history/</id>
    <link rel="enclosure" type="image/jpeg" href="https://nizar.se/uploads/laptop-with-code-on-screen.jpg" />
    <content type="html">
      &lt;img src="https://nizar.se/uploads/laptop-with-code-on-screen.jpg" alt="Laptop displaying code editor with code snippets on the screen" /&gt;
      &lt;p&gt;This blog post is co-authored by &lt;a href=&quot;https://raniz.blog/2022-08-08_look-smarter-with-git/&quot;&gt;Raniz&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Intro&lt;/h1&gt;
&lt;p&gt;As developers, we are encouraged to commit code changes early and frequently. A benefit of which is
being able to revert to previous states when needed. This luxury, however, can come at the expense
of a rather messy Git history; one that communicates how the intended changes were reached rather
than what they are.&lt;/p&gt;
&lt;p&gt;This is considerably noticeable in projects with active main branches, a consequence of the
additional merge commit to a feature branch&#39;s history every time upstream changes are incorporated
into it. Which begs the question, should we strive for a more concise and readable history in favor
of a truly representative one?&lt;/p&gt;
&lt;p&gt;We believe that a Git history that makes it easy for others to follow and understand the history of
a project is a preferable one, a history that focuses on communicating a series of coherent, and
logically separated changes.&lt;/p&gt;
&lt;p&gt;Luckily, Git provides us with the tools to do both. In this post, we present some of our favorite
tools that we use to reorganize intermediate changes into coherent commits and in turn make the
improvements we want to a project&#39;s history.&lt;/p&gt;
&lt;h1&gt;Git Reset&lt;/h1&gt;
&lt;p&gt;Git Reset is often used while working with our staging area; this area is where we add the changes
that we commit when using &lt;code&gt;git commit&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Git reset can be used to rewind history in two ways, by discarding our changes and by keeping them
intact.&lt;/p&gt;
&lt;h2&gt;Hard Reset&lt;/h2&gt;
&lt;p&gt;A hard reset is used to rewind history and discard changes. That is, if we no longer wish to keep
changes made in a previous commit, we can run &lt;code&gt;git reset --hard HEAD~1&lt;/code&gt; and have Git rewind our
branch to the preceding commit.&lt;/p&gt;
&lt;h2&gt;Soft Reset&lt;/h2&gt;
&lt;p&gt;A soft reset works the same way as a hard reset except that it keeps our changes. That is, changes
made in commits that we rewind will be kept in the staging area. This allows us to selectively pick
the changes that we want into one or more new commits.&lt;/p&gt;
&lt;h1&gt;Git Add Patch&lt;/h1&gt;
&lt;p&gt;The Git Add command can be used to not only add entire files to our staging area, but to also
selectively pick lines from one or more changed files.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;git add -p [file]&lt;/code&gt; command contains an optional argument for the path to a file which contains
changes in our repository.&lt;/p&gt;
&lt;p&gt;If no file path is provided, Git will work with every file in the repository that contains changes.
That is, Git will iterate through all the changes and will, for each change, ask whether to add it
to the staging area or not.&lt;/p&gt;
&lt;h1&gt;Git Rebase&lt;/h1&gt;
&lt;p&gt;Git Rebase is used to move one or more commits from one place in the Git history to another.&lt;/p&gt;
&lt;p&gt;For example: Let&#39;s say that we have a project with a main branch and a feature branch, both of which
have two commits added to them after the branching point as illustrated in the figure below.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://nizar.se/uploads/git-branch.svg&quot; alt=&quot;Git branching&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Regular Rebase&lt;/h2&gt;
&lt;p&gt;A regular rebase is often used instead of a merge. To illustrate how it works and how the two
differ, we look at how a merge works.&lt;/p&gt;
&lt;p&gt;When two branches are merged, a new commit is created. This new commit is the intersection point of
two separate histories. If there are any conflicts between the two histories, they are resolved in
the merge commit and added to the history.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://nizar.se/uploads/git-merge.svg&quot; alt=&quot;Git merge&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Rebasing achieves the same goal but does so in a different way. When a branch is rebased, its start
in history is moved from one spot in history to another, most often in front of the last commit on
the branch we would have merged with. That is, we place one branch after the other in history
instead of intersecting two branches.&lt;/p&gt;
&lt;p&gt;Conflicts are resolved during rebasing and commits containing conflicting changes are modified to no
longer be in conflict, effectively removing the conflicts from history.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://nizar.se/uploads/git-rebase.svg&quot; alt=&quot;Git rebase&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;p&gt;As such, a rebase creates a linear history, one that is easier to follow. This is also visible when
viewing the history using a graphical tool; the history looks like a straight line rather than a set
of intertwining parallel tracks.&lt;/p&gt;
&lt;h2&gt;Interactive Rebase&lt;/h2&gt;
&lt;p&gt;An interactive rebase allows us to take full control of the history. This is accomplished by
invoking the &lt;code&gt;git rebase -i &amp;lt;startpoint&amp;gt;&lt;/code&gt; command. &lt;code&gt;startpoint&lt;/code&gt; here is a reference to a commit,
such as a branch or a commit-SHA, in the history from where we want to start making changes.&lt;/p&gt;
&lt;p&gt;Running the command creates a text file that is opened by an editor, allowing us to make changes to
the commit history. Editing this file allows us to, among other things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Reorder commits.&lt;/li&gt;
&lt;li&gt;Remove a commit.&lt;/li&gt;
&lt;li&gt;Combine (squash) commits.&lt;/li&gt;
&lt;li&gt;Edit a commits&#39; message.&lt;/li&gt;
&lt;li&gt;Stop a rebase process, start a shell, and edit the contents of a commit before proceeding.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Together, and with the tools and techniques described above, we are able to to reorder, combine,
split, and edit commits to clean up the history. We can do this once our code is at a point where we
think it is ready for for others to see.&lt;/p&gt;
&lt;h1&gt;When Not To Mess With History&lt;/h1&gt;
&lt;p&gt;It is important to know that you should never rebase a public branch. That is, you should not
rewrite the branch history if someone else shares it. The main branch is an example of such a
branch. Doing so will result in a situation that is tricky to resolve and leaves a confusing
history.&lt;/p&gt;
&lt;p&gt;That said, you are free to do so on your development branches before creating pull requests. In
fact, and as discussed in this post, we believe that such efforts provide valuable improvements for
everyone using the project.&lt;/p&gt;

    </content>
  </entry>
</feed>