<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[ConcurrentFlows - Event Driven Thoughts and Theory]]></title><description><![CDATA[Blog of an Engineering Leader, Event Driven Architect, and new Dad
Engineering Leader | Software Engineer | Event Driven Backend Specialist | C# dotnet Azure]]></description><link>https://concurrentflows.com</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1713412800622/2jHV2IH51.png</url><title>ConcurrentFlows - Event Driven Thoughts and Theory</title><link>https://concurrentflows.com</link></image><generator>RSS for Node</generator><lastBuildDate>Sun, 19 Apr 2026 05:14:49 GMT</lastBuildDate><atom:link href="https://concurrentflows.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[NATS Cluster Architectures: Multiregional Clusters - Connecting the Globe]]></title><description><![CDATA[NATS Topologies for Distributed Systems
In the first part of our NATS Cluster Architectures series, we established robust foundations with regional clusters, covering single-node and three-node NATS deployments. Now, we're ready to expand our horizon...]]></description><link>https://concurrentflows.com/nats-cluster-architectures-multiregional-clusters</link><guid isPermaLink="true">https://concurrentflows.com/nats-cluster-architectures-multiregional-clusters</guid><category><![CDATA[nats]]></category><category><![CDATA[NATSio]]></category><category><![CDATA[C#]]></category><category><![CDATA[event-driven-architecture]]></category><category><![CDATA[messaging]]></category><category><![CDATA[NATS JetStream]]></category><dc:creator><![CDATA[Joshua Steward]]></dc:creator><pubDate>Mon, 09 Jun 2025 19:59:13 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1747521153692/894426f2-d153-4fa2-973c-86a11854fca1.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-nats-topologies-for-distributed-systems">NATS Topologies for Distributed Systems</h1>
<p>In the <a target="_blank" href="https://concurrentflows.com/nats-cluster-architectures-regional-clusters">first part of our NATS Cluster Architectures</a> series, we established robust foundations with regional clusters, covering single-node and three-node NATS deployments. Now, we're ready to expand our horizons and tackle the complexities of connecting your systems across geographical divides.</p>
<p>As applications scale and user bases globalize, bridging data centers or cloud regions becomes essential. NATS excels in these scenarios, offering uniquely flexible multiregional topologies. This installment moves beyond local networks to explore how NATS helps you truly connect the globe.</p>
<p>Here, we'll be diving into:</p>
<ol>
<li><p>Three-Region Superclusters</p>
</li>
<li><p>Leaf Node Deployments</p>
</li>
</ol>
<p>And for each topology, we'll examine:</p>
<ul>
<li><p>Key characteristics and design considerations</p>
</li>
<li><p>Implications for JetStream persistence</p>
</li>
<li><p>Tradeoffs in consistency, latency, and availability</p>
</li>
<li><p>Ideal use cases</p>
</li>
<li><p>Impact on application integration, particularly for C#/.NET clients</p>
</li>
</ul>
<hr />
<h1 id="heading-disaster-ready-multiregional-supercluster">Disaster Ready: Multiregional Supercluster</h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1746951407314/35038e78-55be-4d59-8fd1-0ba4d78d0ff2.png" alt class="image--center mx-auto" /></p>
<p><a target="_blank" href="https://docs.nats.io/running-a-nats-service/configuration/gateways">Superclusters</a> in NATS provide a very high degree of fault tolerance and scalability by interconnecting multiple independent NATS clusters. This allows for resilience across geographically dispersed regions. Here, we'll explore a Supercluster with three regions: Region1, 2 and 3.</p>
<p>In this topology, each region operates as a distinct, three node NATS cluster, as described in the previous section. These regional clusters are then interconnected through <em>Gateways</em>. Gateways establish connections between the regional clusters, allowing for the exchange of messages and subject interest information.</p>
<h2 id="heading-characteristics-at-a-glance">Characteristics at a Glance</h2>
<ul>
<li><p><strong>High Availability:</strong> Failure of an entire region can be tolerated, although some data loss is possible depending on JetStream configuration</p>
</li>
<li><p><strong>Global Scalability:</strong> Scales horizontally by adding more regions or adding servers to existing regions</p>
</li>
<li><p><strong>Geographic Distribution:</strong> Connects NATS deployments across wide-area networks and different geographical locations</p>
</li>
<li><p><strong>Increased Complexity:</strong> Multiple clusters, across multiple regions demands careful, thorough design and configuration with a high level of operational observability and expertise</p>
</li>
<li><p><strong>Potential for Increased Latency:</strong> Cross region communication will naturally have higher latency than local communication</p>
</li>
</ul>
<h2 id="heading-the-nature-of-a-gateway">The nature of a Gateway</h2>
<p>Gateways operate on a dedicated port, separate from client or route ports. They gossip gateway nodes and any discovered gateways. Gateways have several very different characteristics from route connections.</p>
<ul>
<li><p><strong>Named Connections:</strong> Gateway connections themselves are named, specifying their cluster</p>
</li>
<li><p><strong>Gateway Mesh:</strong> A full mesh is formed between clusters instead of between all individual servers</p>
</li>
<li><p><strong>Unidirectional Connections:</strong> Unidirectional connections bind gateways, though discovery makes them appear bidirectional</p>
</li>
<li><p><strong>Client Transparency:</strong> Gateways connections are not gossiped or propagated to clients</p>
</li>
</ul>
<p>Gateway connections are designed to reduce the number of connections required between servers when joining clusters as compared to a full mesh of all servers across all clusters. For instance, with three clusters, each with three nodes; a full mesh routed cluster requires 36 connections, yet only 18 gateway connections are required.</p>
<p>Another key aspect of gateway connections is the optimization of interest graph propagation. This limits unnecessary cross region chatter. Interest propagation across gateways uses mechanisms like <em>Interest-only Mode</em> and <em>Queue Subscriptions</em>. Interest-only requires remote gateways to have explicitly registered interest in a subject. Queue Subscription semantics are honored globally, i.e. messages are delivered to a single subscriber in a queue group across the Supercluster, prioritizing local queue subscribers before failing over to the next lowest RTT cluster.</p>
<h2 id="heading-jetstream-considerations">JetStream Considerations</h2>
<p>JetStream deployed across a Supercluster provides global data distribution, high availability, and fault tolerance. However, resource placement, consistency boundaries and their guarantees must be well understood.</p>
<ul>
<li><p><strong>Local Placement:</strong> Streams and Consumers can only be placed among servers <em>within</em> a cluster, tags across regions will fail to deploy</p>
</li>
<li><p><strong>Local Replication:</strong> Streams and Consumers can only replicate data <em>within</em> a cluster, i.e. across <em>routes</em>, not <em>gateways</em></p>
</li>
<li><p><strong>Meta Group Dependence:</strong> The JetStream Meta Group is made up of the entire Supercluster, if quorum cannot be reached, new resources cannot be created, i.e. new Streams and Consumers</p>
</li>
<li><p><strong>Regional Resilience:</strong> Each region operates its own JetStream resources independently, each with their own RAFT group, even in the loss of a Metagroup quorum, reads/writes to existing resources succeed</p>
</li>
</ul>
<h3 id="heading-replication-and-consistency">Replication and Consistency</h3>
<ul>
<li><p><strong>Within a Region/Cluster:</strong> Strong consistency is ensured within each regional cluster with consensus among all replicas</p>
</li>
<li><p><strong>Mirrored &amp; Sourced Streams:</strong> To achieve fault tolerance across regions Streams can be <em>Mirrored</em> or <em>Sourced,</em> with <em>mirroring</em> being a read-only copy of one Stream and <em>sourced</em> being a locally writeable copy of one or many Streams</p>
</li>
<li><p><strong>Eventual Consistency:</strong> Mirrored &amp; Sourced Streams provide eventual consistency, data written to the source stream(s) will eventually be replicated to the mirrored/sourced stream</p>
</li>
<li><p><strong>Data Loss Possible:</strong> In the event of a catastrophic regional failure, data loss is possible, even with mirroring/sourcing, although loss is limited to the replication window</p>
</li>
</ul>
<h2 id="heading-ideal-use-cases-globally-available-and-disaster-tolerant">Ideal Use Cases - Globally Available and Disaster Tolerant</h2>
<ul>
<li><p><strong>Global Applications:</strong> When users and/or services are distributed across multiple regions</p>
</li>
<li><p><strong>Disaster Tolerance Scenarios:</strong> Where you need to ensure business continuity in the event of a regional outage</p>
</li>
<li><p><strong>Multi Cloud Deployments:</strong> When multiple cloud providers are required, supercluster gateways bridge independent provider clusters</p>
</li>
</ul>
<h2 id="heading-nats-server-config">NATS Server Config</h2>
<p>Getting interesting! This shows how you might configure the servers within one region, <code>region1</code>. Extrapolating to other regions is trivial, and again “self” gateways are smartly ignored.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">port:</span> <span class="hljs-number">4222</span>
<span class="hljs-attr">cluster:</span> {
  <span class="hljs-attr">name:</span> <span class="hljs-string">region1</span>
  <span class="hljs-attr">listen:</span> <span class="hljs-number">0.0</span><span class="hljs-number">.0</span><span class="hljs-number">.0</span><span class="hljs-string">:6222</span>
  <span class="hljs-attr">routes:</span> [
    <span class="hljs-string">"nats://region1-server1:6222"</span>,
    <span class="hljs-string">"nats://region1-server2:6222"</span>,
    <span class="hljs-string">"nats://region1-server3:6222"</span>
  ]
}
<span class="hljs-attr">gateway:</span> {
  <span class="hljs-attr">name:</span> <span class="hljs-string">region1</span>
  <span class="hljs-attr">port:</span> <span class="hljs-number">7222</span>
  <span class="hljs-attr">gateways:</span> [
    { <span class="hljs-attr">name:</span> <span class="hljs-string">"region1"</span>, <span class="hljs-attr">url:</span> <span class="hljs-string">"nats://region1-gateway:7222"</span> },
    { <span class="hljs-attr">name:</span> <span class="hljs-string">"region2"</span>, <span class="hljs-attr">url:</span> <span class="hljs-string">"nats://region2-gateway:7222"</span> },
    { <span class="hljs-attr">name:</span> <span class="hljs-string">"region3"</span>, <span class="hljs-attr">url:</span> <span class="hljs-string">"nats://region3-gateway:7222"</span> }
  ]
}
<span class="hljs-attr">jetstream:</span> {
  <span class="hljs-attr">store_dir:</span> <span class="hljs-string">/data/jetstream</span>
  <span class="hljs-attr">max_memory_store:</span> <span class="hljs-string">1GB</span>
  <span class="hljs-attr">max_file_store:</span> <span class="hljs-string">10GB</span>
}
</code></pre>
<h3 id="heading-key-differences">Key Differences</h3>
<ul>
<li><p><code>cluster.*</code>: Each region has its own cluster configuration, i.e. <code>cluster.name</code>, <code>cluster.listen</code>, <code>routes</code></p>
</li>
<li><p><code>gateway</code>: Section defines how the regional clusters connect</p>
</li>
<li><p><code>gateway.name</code>: Names the cluster, all gateways within a cluster must define the same name</p>
</li>
<li><p><code>gateway.listen</code>: The host and port for incoming gateway connections from other regions</p>
</li>
<li><p><code>gateway.gateways</code>: A list of the gateway addresses of other regions</p>
</li>
</ul>
<h2 id="heading-natsnet-integration">NATS.Net Integration</h2>
<p>Connecting to a NATS Supercluster from a C# application is similar to connecting to a single cluster. Clients connect to a server within their local region. The Supercluster handles the routing of messages across regions.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">const</span> <span class="hljs-keyword">string</span> Region1 = <span class="hljs-string">"region1"</span>;
<span class="hljs-keyword">const</span> <span class="hljs-keyword">string</span> Region2 = <span class="hljs-string">"region2"</span>;
<span class="hljs-keyword">var</span> loggerFactory = LoggerFactory.Create(builder =&gt; builder.AddConsole());
<span class="hljs-keyword">var</span> logger = loggerFactory.CreateLogger&lt;Program&gt;();

<span class="hljs-keyword">using</span> <span class="hljs-keyword">var</span> cts = <span class="hljs-keyword">new</span> CancellationTokenSource(TimeSpan.FromSeconds(<span class="hljs-number">10</span>));
<span class="hljs-keyword">var</span> subscribing = Region2JetStreamSubscribeAsync(cts.Token);
<span class="hljs-keyword">var</span> publishing = Region1JetStreamPublishAsync(cts.Token);

<span class="hljs-keyword">await</span> Task.WhenAll(publishing, subscribing);

<span class="hljs-function"><span class="hljs-keyword">async</span> Task <span class="hljs-title">Region1JetStreamPublishAsync</span>(<span class="hljs-params">CancellationToken token</span>)</span>
{
    <span class="hljs-keyword">var</span> context = GetRegion1JetStreamContext();
    Placement placement = <span class="hljs-keyword">new</span>() { Cluster = Region1 };
    <span class="hljs-keyword">var</span> streamConfig = <span class="hljs-keyword">new</span> StreamConfig(<span class="hljs-string">$"<span class="hljs-subst">{Region1}</span>-stream"</span>, [<span class="hljs-string">$"<span class="hljs-subst">{Region1}</span>.&gt;"</span>])
    {
        NumReplicas = <span class="hljs-number">3</span>,
        Placement = placement
    };
    _ = <span class="hljs-keyword">await</span> context.CreateOrUpdateStreamAsync(streamConfig, token);

    <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> id <span class="hljs-keyword">in</span> Enumerable.Range(<span class="hljs-number">1</span>, <span class="hljs-number">10</span>))
        <span class="hljs-keyword">await</span> context.PublishAsync(<span class="hljs-string">$"<span class="hljs-subst">{Region1}</span>.data"</span>, <span class="hljs-string">$"From <span class="hljs-subst">{Region1}</span>: <span class="hljs-subst">{id}</span>"</span>, cancellationToken: token);

    logger.LogInformation(<span class="hljs-string">"{Region} client completed publishing"</span>, Region1);
}

<span class="hljs-function"><span class="hljs-keyword">async</span> Task <span class="hljs-title">Region2JetStreamSubscribeAsync</span>(<span class="hljs-params">CancellationToken token</span>)</span>
{
    <span class="hljs-keyword">var</span> context = GetRegion2JetStreamContext();
    Placement placement = <span class="hljs-keyword">new</span>() { Cluster = Region2 };
    SubjectTransform transform = <span class="hljs-keyword">new</span>() { Src = <span class="hljs-string">$"<span class="hljs-subst">{Region1}</span>.&gt;"</span>, Dest = <span class="hljs-string">$"<span class="hljs-subst">{Region2}</span>.from-<span class="hljs-subst">{Region1}</span>.&gt;"</span> };
    StreamSource source = <span class="hljs-keyword">new</span>()
    {
        Name = <span class="hljs-string">$"<span class="hljs-subst">{Region1}</span>-stream"</span>,
        SubjectTransforms = [transform]
    };
    <span class="hljs-keyword">var</span> streamConfig = <span class="hljs-keyword">new</span> StreamConfig(<span class="hljs-string">$"<span class="hljs-subst">{Region2}</span>-stream"</span>, [<span class="hljs-string">$"<span class="hljs-subst">{Region2}</span>.&gt;"</span>])
    {
        NumReplicas = <span class="hljs-number">3</span>,
        Placement = placement,
        Sources = [source]
    };
    <span class="hljs-keyword">var</span> stream = <span class="hljs-keyword">await</span> context.CreateOrUpdateStreamAsync(streamConfig, token);
    <span class="hljs-keyword">var</span> consumer = <span class="hljs-keyword">await</span> stream.CreateOrderedConsumerAsync(cancellationToken: token);

    <span class="hljs-keyword">await</span> <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> msg <span class="hljs-keyword">in</span> consumer.ConsumeAsync&lt;<span class="hljs-keyword">string</span>&gt;(cancellationToken: token))
    {
        logger.LogInformation(<span class="hljs-string">"{Region} client received: {Message}"</span>, Region2, msg.Data);
        <span class="hljs-keyword">await</span> msg.AckAsync(cancellationToken: token);
    }
}

<span class="hljs-function">INatsJSContext <span class="hljs-title">GetRegion1JetStreamContext</span>(<span class="hljs-params"></span>)</span>
    =&gt; <span class="hljs-keyword">new</span> NatsJSContext(BuildNatsConnection(Region1));

<span class="hljs-function">INatsJSContext <span class="hljs-title">GetRegion2JetStreamContext</span>(<span class="hljs-params"></span>)</span>
    =&gt; <span class="hljs-keyword">new</span> NatsJSContext(BuildNatsConnection(Region2));

<span class="hljs-function">INatsConnection <span class="hljs-title">BuildNatsConnection</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> region</span>)</span>
    =&gt; <span class="hljs-keyword">new</span> NatsConnection(<span class="hljs-keyword">new</span>()
    {
        Url = <span class="hljs-string">$"nats://<span class="hljs-subst">{region}</span>1:4222,nats://<span class="hljs-subst">{region}</span>2:4222,nats://<span class="hljs-subst">{region}</span>3:4222"</span>,
        LoggerFactory = loggerFactory
    });
</code></pre>
<h3 id="heading-key-differences-1">Key Differences</h3>
<p>This sample becomes a bit more complex but showcases much more functionality.</p>
<ul>
<li><p><code>Region1JetStreamPublishAsync</code></p>
<ul>
<li><p>Creates a region local stream, <code>region1-stream</code></p>
</li>
<li><p>Consumes all subjects matching <code>region1.&gt;</code></p>
</li>
<li><p>Finally, publishes 10 messages to <code>region1.data</code> that get ingested into <code>region1-stream</code></p>
</li>
</ul>
</li>
<li><p><code>Region2JetStreamSubscribeAsync</code></p>
<ul>
<li><p>Creates a region local stream, <code>region2-stream</code></p>
</li>
<li><p>Consumes all subjects matching <code>region2.&gt;</code></p>
</li>
<li><p>Also, <em>Sources</em> <code>region1-stream</code>, replicating all data locally</p>
</li>
<li><p>Then <em>Transforms</em> all inbound <code>region1.&gt;</code> subjects to an east-centric version, <code>region2.from-region1.&gt;</code></p>
</li>
<li><p>Finally, consumes all available messages via an ephemeral ordered Consumer</p>
</li>
</ul>
</li>
</ul>
<hr />
<h1 id="heading-localized-reliability-leaf-nodes">Localized Reliability: Leaf Nodes</h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747489005119/ec59c0a6-da37-4fd1-885a-8e29e5525d5a.png" alt class="image--center mx-auto" /></p>
<p><a target="_blank" href="https://docs.nats.io/running-a-nats-service/configuration/leafnodes">Leaf Nodes</a> extend an existing NATS deployment, be it single server, cluster, supercluster, etc., to conceptually edge deployments. This creates an isolation boundary and local resiliency with respect to the remote <em>Hub</em>. Leaf Nodes provide communication connectivity locally within their edge boundary even when disconnected from the remote. Unlike servers in the remote hub cluster, Leaf Nodes do not participate in the same routing mesh. Instead, they establish an account scoped point-to-point connection(s) to the remote. Further, Leaf Nodes themselves do not need to be reachable by clients but instead can be used to form any acyclic topology.</p>
<p>Client reachable Leaf Nodes present a discrete NATS context distinct from that of the remote. Clients connect against a local AuthN/AuthZ policy of the Leaf Node, and the Leaf Node forwards messages to and from the remote. Only the credentials required to form the Leaf Node to hub connection need be shared between the domains, allowing security and generally <em>Operator</em> domains to be bridged. The remote hub sees the Leaf Node as a single account scoped connection, carrying with it the permissions, exports, and imports of that account.</p>
<h2 id="heading-characteristics-at-a-glance-1">Characteristics at a Glance</h2>
<ul>
<li><p><strong>Network Segmentation:</strong> Leaf Nodes represent isolated segments, preventing unnecessary traffic from crossing network boundaries</p>
</li>
<li><p><strong>Connection Schemes:</strong> Leaf Nodes can connect to their remote via plain TCP, TLS, and even WebSockets</p>
</li>
<li><p><strong>Controlled Connectivity:</strong> Account/User level configuration provides fine grained control over which subjects are exchanged with the upstream</p>
</li>
<li><p><strong>Resilience:</strong> Leaf Nodes provide localized resilience, if the connection to the remote is lost, clients within the Leaf Node's network segment can still communicate with each other</p>
</li>
<li><p><strong>Distinct AuthN/AuthZ:</strong> Clients of the Leaf Node connect against the local auth policy, while the Leaf Node connection to the remote is a separate shared policy</p>
</li>
</ul>
<h2 id="heading-jetstream-considerations-1">JetStream Considerations</h2>
<p>Leaf Nodes can either extend or isolate a JetStream <em>Domain</em>. The JetStream Domain is an independent namespace within JetStream that disambiguates requests between NATS deployments. Extending a central JetStream deployment through a leaf deployment would map to the same domain. While isolating JetStream deployments accessible to the same client would be done via unique JetStream domain names.</p>
<ul>
<li><p><strong>Isolated Domains:</strong> Leaf Nodes can isolate JetStream domains, selectively sharing between the independent namespaces</p>
</li>
<li><p><strong>Data Resiliency:</strong> JetStream data is stored locally on the Leaf Node, ensuring that data is preserved even if the connection to a remote is temporarily lost</p>
</li>
<li><p><strong>Data Locality:</strong> Ensures data locality for compliance or performance reasons</p>
</li>
<li><p><strong>Consistency Separation:</strong> Leaf local streams can be immediately consistent, while streams shared across the Leaf node connection can be eventually consistent via sourcing/mirroring to/from the remote</p>
</li>
</ul>
<h2 id="heading-ideal-use-cases-segmented-or-intermittent-connectivity">Ideal Use Cases - Segmented or Intermittent Connectivity</h2>
<ul>
<li><p><strong>Remote Distribution:</strong> Connecting NATS servers in different, remote locations, such as disparate local offices, remote sites, etc.</p>
</li>
<li><p><strong>Organization Separation:</strong> Leaf Nodes bridge security and operator domains allowing zero trust between separate entities</p>
</li>
<li><p><strong>Edge Computing:</strong> Deploying Leaf Nodes at the edge of the network to collect and process data locally before forwarding it to a central system</p>
</li>
<li><p><strong>Network Segmentation:</strong> Isolating different parts of your network for security or performance reasons</p>
</li>
<li><p><strong>Data Localization:</strong> Keeping data within a specific region or network segment for compliance or performance</p>
</li>
</ul>
<h2 id="heading-nats-server-config-1">NATS Server Config</h2>
<p>Leaf Node server config becomes a bit more involved and needs to be well planned. Here, we see a shared account between the Hub and Leaf, while each may have other respective local accounts.</p>
<h3 id="heading-accountssharedconf"><code>accounts.shared.conf</code></h3>
<pre><code class="lang-yaml"><span class="hljs-attr">accounts:</span> {
  <span class="hljs-attr">SYS:</span> {
    <span class="hljs-attr">users:</span> [{ <span class="hljs-attr">user:</span> <span class="hljs-string">sys</span>, <span class="hljs-attr">password:</span> <span class="hljs-string">sys</span> }]
  },
  <span class="hljs-attr">LEAF:</span> {
    <span class="hljs-attr">users:</span> [{ <span class="hljs-attr">user:</span> <span class="hljs-string">leaf</span>, <span class="hljs-attr">password:</span> <span class="hljs-string">leaf</span> }],
    <span class="hljs-attr">jetstream:</span> <span class="hljs-string">enabled</span>
  }
}
<span class="hljs-attr">system_account:</span> <span class="hljs-string">SYS</span>
</code></pre>
<h3 id="heading-serverhubconf"><code>server.hub.conf</code></h3>
<pre><code class="lang-yaml"><span class="hljs-attr">port:</span> <span class="hljs-number">4222</span>
<span class="hljs-attr">server_name:</span> <span class="hljs-string">hub</span>
<span class="hljs-string">include</span> <span class="hljs-string">./accounts.conf</span>
<span class="hljs-attr">jetstream:</span> {
  <span class="hljs-attr">store_dir:</span> <span class="hljs-string">/data/jetstream</span>
  <span class="hljs-attr">domain:</span> <span class="hljs-string">hub</span>
  <span class="hljs-attr">max_memory_store:</span> <span class="hljs-string">1GB</span>
  <span class="hljs-attr">max_file_store:</span> <span class="hljs-string">10GB</span>
}
<span class="hljs-attr">leafnodes:</span> {
  <span class="hljs-attr">port:</span> <span class="hljs-number">7422</span>
}
</code></pre>
<h3 id="heading-serverleafconf"><code>server.leaf.conf</code></h3>
<pre><code class="lang-yaml"><span class="hljs-attr">port:</span> <span class="hljs-number">4222</span>
<span class="hljs-attr">server_name:</span> <span class="hljs-string">leaf-node</span>
<span class="hljs-string">include</span> <span class="hljs-string">./accounts.conf</span>
<span class="hljs-attr">jetstream:</span> {
  <span class="hljs-attr">store_dir:</span> <span class="hljs-string">/data/jetstream</span>
  <span class="hljs-attr">domain:</span> <span class="hljs-string">leaf</span>
  <span class="hljs-attr">max_memory_store:</span> <span class="hljs-string">1GB</span>
  <span class="hljs-attr">max_file_store:</span> <span class="hljs-string">10GB</span>
}
<span class="hljs-attr">leafnodes:</span> {
  <span class="hljs-attr">remotes:</span> [
    {
      <span class="hljs-attr">urls:</span> [<span class="hljs-string">"nats://leaf:leaf@0.0.0.0:7422"</span>]
      <span class="hljs-attr">account:</span> <span class="hljs-string">"LEAF"</span>
    }
  ]
}
</code></pre>
<h3 id="heading-key-differences-2">Key Differences</h3>
<ul>
<li><p><code>accounts.shared.conf</code><strong>:</strong> LEAF account is shared and used to connect the Leaf Node back to the Hub</p>
</li>
<li><p><code>jetstream.domain</code>: Defines separate isolated JetStream Domains, namespaces, for the Leaf Node and Hub</p>
</li>
<li><p><strong>Hub</strong> <code>leafnodes.*</code>: Enables the server to listen for Leaf Node connections on the specified port</p>
</li>
<li><p><strong>Leaf</strong> <code>leafnodes.*</code>: Configures a Leaf Node connection back to the Hub on the specified port, using the shared Account and User</p>
</li>
</ul>
<h2 id="heading-natsnet-integration-1">NATS.Net Integration</h2>
<p>Connecting to a Leaf Node from a C# application is much the same as connecting to any NATS server. The client authenticates with a local account and is unaware that it's connected to a Leaf Node or that there is anything ‘upstream’.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> loggerFactory = LoggerFactory.Create(builder =&gt; builder.AddConsole());
<span class="hljs-keyword">var</span> logger = loggerFactory.CreateLogger&lt;Program&gt;();

<span class="hljs-keyword">using</span> <span class="hljs-keyword">var</span> cts = <span class="hljs-keyword">new</span> CancellationTokenSource(TimeSpan.FromSeconds(<span class="hljs-number">10</span>));
<span class="hljs-keyword">var</span> opts = <span class="hljs-keyword">new</span> NatsOpts
{
    Url = <span class="hljs-string">"nats://leaf:leaf@leaf-node:4222"</span>,
    LoggerFactory = loggerFactory
};

<span class="hljs-keyword">await</span> <span class="hljs-keyword">using</span> <span class="hljs-keyword">var</span> connection = <span class="hljs-keyword">new</span> NatsConnection(opts);
<span class="hljs-keyword">var</span> context = <span class="hljs-keyword">new</span> NatsJSContext(connection);

<span class="hljs-keyword">var</span> streamConfig = <span class="hljs-keyword">new</span> StreamConfig(<span class="hljs-string">"local-stream"</span>, [<span class="hljs-string">"leaf.&gt;"</span>]);
<span class="hljs-keyword">var</span> stream = <span class="hljs-keyword">await</span> context.CreateStreamAsync(streamConfig, cts.Token);
<span class="hljs-keyword">var</span> consumer = <span class="hljs-keyword">await</span> stream.CreateOrderedConsumerAsync(cancellationToken: cts.Token);

<span class="hljs-keyword">await</span> context.PublishAsync&lt;<span class="hljs-keyword">string</span>&gt;(<span class="hljs-string">"leaf.data"</span>, <span class="hljs-string">"Hello World"</span>);

<span class="hljs-keyword">var</span> msg = <span class="hljs-keyword">await</span> consumer.NextAsync&lt;<span class="hljs-keyword">string</span>&gt;(cancellationToken: cts.Token);
logger.LogInformation(<span class="hljs-string">"Leaf received: {Message}"</span>, msg?.Data);
<span class="hljs-keyword">await</span> (msg?.AckAsync(cancellationToken: cts.Token) ?? ValueTask.CompletedTask);

<span class="hljs-keyword">await</span> connection.PublishAsync(<span class="hljs-string">"remote.data"</span>, <span class="hljs-string">"Message to Remote"</span>, cancellationToken: cts.Token);
</code></pre>
<hr />
<h1 id="heading-wrap-up">Wrap Up</h1>
<p>The second part of the NATS Topologies set expanded our focus and explored two key NATS topologies:</p>
<ul>
<li><p><strong>Superclusters:</strong> Understood how Superclusters interconnect independent NATS clusters across regions, providing high availability and examined JetStream replication and consistency in a multi-regional context</p>
</li>
<li><p><strong>Leaf Nodes:</strong> Then we discussed how Leaf Nodes enable you to extend a central NATS deployment across different networks, and isolated security domains, also highlighting the unique implications of isolated JetStream domains</p>
</li>
</ul>
<p>But there's still more to discover!</p>
<h2 id="heading-next-up-advanced-topologies">Next Up - Advanced Topologies!</h2>
<p>In <strong>Part 3: Advanced Topologies</strong>, we'll push the boundaries of NATS even further, literally! First, we’ll be exploring the nature of a Stretch Cluster and how it differs from a Supercluster. Then, we’ll look at the Leaf Cluster, trading immediate consistency for greater resiliency. Get ready to master some of the most powerful and intricate NATS architectures!</p>
<p><strong><em>Have a specific question about NATS? Want a specific topic covered? Drop it in the comments!</em></strong></p>
]]></content:encoded></item><item><title><![CDATA[NATS Cluster Architectures: Regional Clusters - Building Reliable Messaging Foundations]]></title><description><![CDATA[Why does NATS topology matter?
NATS topology refers to the way your NATS servers are arranged and connected. Unlike many messaging systems with more rigid deployment models, NATS offers remarkable flexibility. You're not shoehorned into a one-size-fi...]]></description><link>https://concurrentflows.com/nats-cluster-architectures-regional-clusters</link><guid isPermaLink="true">https://concurrentflows.com/nats-cluster-architectures-regional-clusters</guid><category><![CDATA[NATS JetStream]]></category><category><![CDATA[nats]]></category><category><![CDATA[NATSio]]></category><category><![CDATA[C#]]></category><category><![CDATA[event-driven-architecture]]></category><category><![CDATA[messaging]]></category><dc:creator><![CDATA[Joshua Steward]]></dc:creator><pubDate>Fri, 30 May 2025 04:09:57 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1747505796050/1cf2c368-1d31-4e8e-8a57-3b7d1298df72.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-why-does-nats-topology-matter">Why does NATS topology matter?</h1>
<p>NATS topology refers to the way your NATS servers are arranged and connected. Unlike many messaging systems with more rigid deployment models, NATS offers remarkable flexibility. You're not shoehorned into a one-size-fits-all approach; instead, <em>you become the architect of your messaging fabric.</em></p>
<p>Your choice of topology, whether a single server, resilient cluster, leaf nodes, a supercluster, etc. will directly shape fault tolerance, message delivery guarantees, network segmentation, and overall system complexity. This means you can tailor your NATS deployment precisely to your needs, but it requires careful consideration.</p>
<p>This miniseries of posts will explore a variety of NATS server topologies, increasing in their complexity. Here, we’ll be covering:</p>
<ol>
<li><p>The single instance deployment</p>
</li>
<li><p>A resilient three-node cluster</p>
</li>
</ol>
<p>And for each:</p>
<ul>
<li><p>Key characteristics of each topology</p>
</li>
<li><p>Tradeoffs in consistency, latency, and availability</p>
</li>
<li><p>Potential use cases</p>
</li>
<li><p>Impact on application integration, particularly within C#/.NET clients</p>
</li>
</ul>
<hr />
<h1 id="heading-the-singularity-single-nats-server">The Singularity: Single NATS Server</h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1746861001156/f531aecc-f904-42e2-93c2-e163ab66aae4.png" alt class="image--center mx-auto" /></p>
<p>A <a target="_blank" href="https://docs.nats.io/running-a-nats-service/configuration">single NATS server</a> is the most fundamental setup, deployed as a single instance of the NATS server. It's the easiest to grasp and get started with, making it a natural entry point for development and simple use cases. This is the same deployment we used in “<a target="_blank" href="https://concurrentflows.com/getting-started-with-nats-in-c">Getting Started with NATS in C#</a>”</p>
<p>In this topology, a single NATS server process handles all client connections, message routing, and any configured persistence, i.e. JetStream, if enabled. All publishers and subscribers within our system connect directly to this single endpoint.</p>
<h2 id="heading-characteristics-at-a-glance">Characteristics at a Glance</h2>
<ul>
<li><p><strong>Simplicity:</strong> Straightforward to configure and manage</p>
</li>
<li><p><strong>Low Overhead:</strong> Requires the least amount of infrastructure resources, i.e. CPU, memory, network</p>
</li>
<li><p><strong>Single Point of Failure:</strong> If the server becomes unavailable due to hardware failure, network issues, or software problems, the entire messaging system halts</p>
</li>
<li><p><strong>Limited Scalability:</strong> The performance and throughput of the system are bounded by the capacity of the single server instance</p>
<ul>
<li><em>Note: Although, a single NATS server can still be quite performant, to the tune of millions of messages/sec depending on resources</em></li>
</ul>
</li>
<li><p><strong>No Redundancy:</strong> Availability limited to the single node, no automatic failover or backup</p>
</li>
<li><p><strong>No JetStream Replication:</strong> Of course, with a single server, no JetStream resources can be replicated</p>
</li>
</ul>
<h2 id="heading-ideal-use-cases-devlocalnon-prod">Ideal Use Cases - Dev/Local/Non-Prod</h2>
<ul>
<li><p><strong>Local Dev and Testing:</strong> Perfect for a local dev NATS environment and local integration testing</p>
</li>
<li><p><strong>Demos, POCs:</strong> Proving new messaging patterns among microservices, demoing new features, etc.</p>
</li>
<li><p><strong>Learning and Exploration:</strong> Low barrier of entry to understand the basic concepts of NATS without the complexities of clustering</p>
</li>
</ul>
<h2 id="heading-nats-server-config">NATS Server Config</h2>
<p>Couldn’t be simpler! This specifies that clients should connect on the default port <code>4222</code> and the server will be listening on <code>0.0.0.0:4222</code></p>
<pre><code class="lang-yaml"><span class="hljs-attr">port:</span> <span class="hljs-number">4222</span>
</code></pre>
<p>Mounting a file for just this might be overkill, you can simply specify many options via the command line as well. While <code>4222</code> is the default, just for example, with Docker, this is equivalent to the <code>server.conf</code> above</p>
<pre><code class="lang-apache"><span class="hljs-attribute">docker</span> run --rm --name my-nats -p <span class="hljs-string">"4222:4222"</span> nats -p <span class="hljs-number">4222</span>
</code></pre>
<h2 id="heading-natsnet-integration">NATS.Net Integration</h2>
<p>Connecting to a single NATS server will use a connection string pointing to its address, just the same as we saw in “<a target="_blank" href="https://concurrentflows.com/getting-started-with-nats-in-c">Getting Started with NATS in C#</a>”. For completeness, the <a target="_blank" href="https://github.com/nats-io/nats.net#">NATS.NET client library</a> provides the tools for this. Importantly, in this topology, our app becomes directly reliant on the availability of this single server. As a result, several factors will impact our app design.</p>
<ul>
<li><p><strong>Connection Management:</strong> The <code>NATS.Client.Core</code> library does provide robust connection management, but with a single server, its primarily focused on the initial connection and handling disconnects</p>
</li>
<li><p><strong>Initial Connection:</strong> By default, the client will lazily connect to the server, and fail fast on the initial connection attempt, i.e. the initial attempt is not retried and a <code>NatsException</code> is thrown</p>
</li>
<li><p><strong>Reconnects:</strong> After an initial successful connection, any drop will result in a reconnect attempt up to a configured limit via <code>NatsOpts.*Reconnect*</code> properties</p>
</li>
<li><p><strong>No Automatic Failover:</strong> Reconnection attempts have no other route except the same single address</p>
</li>
</ul>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> loggerFactory = LoggerFactory.Create(builder =&gt; builder.AddConsole());
<span class="hljs-keyword">var</span> logger = loggerFactory.CreateLogger&lt;Program&gt;();

<span class="hljs-keyword">var</span> opts = <span class="hljs-keyword">new</span> NatsOpts
{
    Url = <span class="hljs-string">"nats://localhost:4222"</span>,
    LoggerFactory = loggerFactory
};

<span class="hljs-keyword">await</span> <span class="hljs-keyword">using</span> <span class="hljs-keyword">var</span> connection = <span class="hljs-keyword">new</span> NatsConnection(opts);

<span class="hljs-keyword">var</span> rtt = <span class="hljs-keyword">await</span> connection.PingAsync(CancellationToken.None);

logger.LogInformation(<span class="hljs-string">"Ping successful - {RTT}ms to {@ServerInfo}"</span>,
    rtt.TotalMilliseconds,
    connection.ServerInfo);
</code></pre>
<hr />
<h1 id="heading-resilience-through-redundancy-three-node-cluster">Resilience Through Redundancy: Three Node Cluster</h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1746861504850/480dd17e-45c1-4840-92ac-861322c4f82f.png" alt class="image--center mx-auto" /></p>
<p><a target="_blank" href="https://docs.nats.io/running-a-nats-service/configuration/clustering">Clustering in NATS</a> provides fault tolerance and increased capacity by connecting multiple NATS servers. A cluster of three nodes is a common starting point for production deployments and offers a balance between resilience and complexity.</p>
<p>In this topology, three NATS servers are interconnected via routes, and form a full mesh. Each server maintains bidirectional connections to the others, allowing them to fully propagate the Subject interest graph. Clients can connect to any server in the cluster, and the cluster will route messages appropriately, even if a server becomes unavailable.</p>
<h2 id="heading-characteristics-at-a-glance-1">Characteristics at a Glance</h2>
<ul>
<li><p><strong>Fault Tolerance &amp; Increased Availability:</strong> The cluster can still serve Core NATS traffic even in the face of a two node failure, i.e. operates with only a single node</p>
</li>
<li><p><strong>Improved Scalability:</strong> Distributes the load across multiple servers, increasing the overall capacity of the system.</p>
</li>
<li><p><strong>Automatic Discovery:</strong> NATS servers in a cluster will automatically discover each other after reaching any ‘seed’ server, cluster gossip ensures a full mesh is maintained</p>
</li>
<li><p><strong>Message Routing:</strong> Servers route messages to the appropriate destinations within the cluster, cluster is transparent to publisher/subscribers beyond any connection string</p>
</li>
<li><p><strong>Increased Complexity:</strong> Although still minimal, configuring and managing a cluster does involve more complexity than a single server</p>
</li>
</ul>
<h2 id="heading-jetstream-considerations">JetStream Considerations</h2>
<p>Clustering is crucial for JetStream's fault tolerance and data durability. JetStream leverages the Raft consensus algorithm to replicate data across multiple servers within a cluster. This ensures, to the limit of consensus, that the data remains available and consistent.</p>
<ul>
<li><p><strong>Quorum:</strong> JetStream requires a quorum, \(1/2*n+1\), to be available in order to handle requests, e.g. reads, writes, acks, etc.</p>
</li>
<li><p><strong>Storage:</strong> Each server in the cluster needs its own storage for JetStream data</p>
</li>
<li><p><strong>Replication Latency:</strong> Replication adds some network overhead, low latency network connections are critical</p>
</li>
</ul>
<h3 id="heading-replication-and-consistency">Replication and Consistency</h3>
<ul>
<li><p><strong>Replication Factor:</strong> With three nodes, 3x replication of JetStream Stream and Consumer data/metadata can be achieved</p>
</li>
<li><p><strong>Consistency:</strong> Raft ensures strong consistency, meaning that all replicas agree on the order of the data</p>
<ul>
<li><em>Note: Replication is set at the Stream level and either inherited or optionally set at the Consumer level, “In Sync Replicas” will always be equal to Replicas, i.e.</em> <code>acks = all</code></li>
</ul>
</li>
<li><p><strong>Fault Tolerance:</strong> A replication factor of 3 allows the cluster to tolerate the failure of up to one server without losing any data, and continuing servicing requests</p>
</li>
<li><p><strong>Increased Durability:</strong> Storing multiple copies of the data significantly reduces the risk of data loss due to hardware failures or other issues</p>
</li>
</ul>
<h2 id="heading-ideal-use-cases-single-region-production">Ideal Use Cases - Single Region Production</h2>
<ul>
<li><p><strong>Single Region Production Environments:</strong> Essential for any production system that requires high availability and fault tolerance</p>
</li>
<li><p><strong>Durable, Highly Available Apps:</strong> Applications where data loss or downtime is unacceptable</p>
</li>
<li><p><strong>Scalable Systems:</strong> Systems that need to handle a high volume of messages and clients</p>
</li>
</ul>
<h2 id="heading-nats-server-config-1">NATS Server Config</h2>
<p>A basic example of a <code>server.conf</code>, you could create three separate configuration files (server1.conf, server2.conf, and server3.conf), each with the appropriate settings for that particular server. Although, the config can be reused depending on your networking environment. Note that routes pointed to “self” are smartly ignored making config sharing a bit easier.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">listen:</span> <span class="hljs-number">0.0</span><span class="hljs-number">.0</span><span class="hljs-number">.0</span><span class="hljs-string">:4222</span>
<span class="hljs-string">cluster</span> {
  <span class="hljs-attr">name:</span> <span class="hljs-string">my-cluster</span>
  <span class="hljs-attr">listen:</span> <span class="hljs-number">0.0</span><span class="hljs-number">.0</span><span class="hljs-number">.0</span><span class="hljs-string">:6222</span>
  <span class="hljs-attr">routes:</span> [
    <span class="hljs-string">"nats://server1:6222"</span>,
    <span class="hljs-string">"nats://server2:6222"</span>,
    <span class="hljs-string">"nats://server3:6222"</span>
  ]
}
<span class="hljs-string">jetstream</span> {
  <span class="hljs-attr">store_dir:</span> <span class="hljs-string">/data/jetstream</span>
  <span class="hljs-attr">max_memory_store:</span> <span class="hljs-string">1GB</span>
  <span class="hljs-attr">max_file_store:</span> <span class="hljs-string">10GB</span>
}
</code></pre>
<h3 id="heading-key-differences">Key Differences</h3>
<ul>
<li><p><code>cluster</code>: Section defines the details of our cluster</p>
</li>
<li><p><code>cluster.name</code>: Uniquely identifies the cluster</p>
</li>
<li><p><code>cluster.listen</code>: The host and port to listen on for incoming clustering connections</p>
</li>
<li><p><code>cluster.routes</code>: A list of dedicated Routes to other servers</p>
</li>
<li><p><code>jetstream</code>: Configures JetStream, including storage target and limits</p>
</li>
</ul>
<h2 id="heading-natsnet-integration-1">NATS.Net Integration</h2>
<p>Connecting to a NATS cluster with the <code>NATS.Client.Core</code> and <code>NATS.Client.JetStream</code> libraries is straightforward. This time, you can provide a list of server URLs, and the client will automatically connect to the first available server. If that server becomes unavailable, the client will attempt to connect to another server in the list.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> loggerFactory = LoggerFactory.Create(builder =&gt; builder.AddConsole());
<span class="hljs-keyword">var</span> logger = loggerFactory.CreateLogger&lt;Program&gt;();

<span class="hljs-keyword">var</span> opts = <span class="hljs-keyword">new</span> NatsOpts
{
    Url = <span class="hljs-string">"nats://server1:4222,nats://server2:4222,nats://server3:4222"</span>,
    LoggerFactory = loggerFactory
};

<span class="hljs-keyword">var</span> connection = <span class="hljs-keyword">await</span> GetConnectionAsync(logger, opts);
<span class="hljs-keyword">var</span> stream = <span class="hljs-keyword">await</span> GetStreamAsync(logger, connection);

<span class="hljs-function"><span class="hljs-keyword">async</span> Task&lt;INatsConnection&gt; <span class="hljs-title">GetConnectionAsync</span>(<span class="hljs-params">ILogger logger, NatsOpts opts</span>)</span>
{
    <span class="hljs-keyword">await</span> <span class="hljs-keyword">using</span> <span class="hljs-keyword">var</span> connection = <span class="hljs-keyword">new</span> NatsConnection(opts);

    <span class="hljs-keyword">var</span> rtt = <span class="hljs-keyword">await</span> connection.PingAsync(CancellationToken.None);

    logger.LogInformation(<span class="hljs-string">"Ping successful - {RTT}ms to {@ServerInfo}"</span>,
        rtt.TotalMilliseconds,
        connection.ServerInfo);
    <span class="hljs-keyword">return</span> connection;
}

<span class="hljs-function"><span class="hljs-keyword">async</span> Task&lt;INatsJSStream&gt; <span class="hljs-title">GetStreamAsync</span>(<span class="hljs-params">ILogger logger, INatsConnection connection</span>)</span>
{
    <span class="hljs-keyword">var</span> context = <span class="hljs-keyword">new</span> NatsJSContext(connection);
    <span class="hljs-keyword">var</span> config = <span class="hljs-keyword">new</span> StreamConfig(<span class="hljs-string">"my-first-stream"</span>, [<span class="hljs-string">"some.subjects.&gt;"</span>])
    {
        NumReplicas = <span class="hljs-number">3</span>
    };

    <span class="hljs-keyword">var</span> stream = <span class="hljs-keyword">await</span> context.CreateOrUpdateStreamAsync(config, CancellationToken.None);
    logger.LogInformation(<span class="hljs-string">"Stream created/updated - {@StreamInfo}"</span>, stream.Info);
    <span class="hljs-keyword">return</span> stream;
}
</code></pre>
<h3 id="heading-key-differences-1">Key Differences</h3>
<ul>
<li><p><code>NatsOpts.Url</code>: Set to a comma separated list of server URLs</p>
</li>
<li><p><code>NATS.Client.Core</code>: Handles connecting among multiple servers, starting with the first available server and reconnecting to another server if the connection is lost</p>
</li>
<li><p><code>NatsJSContext</code>: Building on top of Core NATS, the JetStream Context accepts an existing <code>NatsConnection</code></p>
</li>
<li><p><code>my-first-stream</code>: Configured with a replication factor of 3, ensuring that data is replicated across all three servers in the cluster</p>
</li>
</ul>
<hr />
<h1 id="heading-wrap-up">Wrap Up</h1>
<p>In this first part exploring NATS topologies, from single to three node cluster, we've laid the groundwork for building robust and scalable messaging systems with NATS.</p>
<h2 id="heading-next-up-multiregional-clusters">Next Up - Multiregional Clusters!</h2>
<p>Moving beyond single region clusters, we're now ready to take our NATS deployments to the next level. In <strong>Part 2: Multiregional Clusters</strong>, we'll dive into how Superclusters and Leaf Nodes enable you to connect NATS deployments across geographical distances, building resilient and scalable messaging solutions that span the globe. Get ready to unleash the full potential of NATS for distributed, mission-critical applications!</p>
<p><strong><em>Have a specific question about NATS? Want a specific topic covered? Drop it in the comments!</em></strong></p>
]]></content:encoded></item><item><title><![CDATA[Getting Started with NATS in C#]]></title><description><![CDATA[Beginning with NATS
In the world of distributed systems, event driven architecture, EDA, has emerged as a powerful paradigm for building scalable and resilient applications. At the heart of many EDA implementations lies a robust messaging system, and...]]></description><link>https://concurrentflows.com/getting-started-with-nats-in-csharp</link><guid isPermaLink="true">https://concurrentflows.com/getting-started-with-nats-in-csharp</guid><category><![CDATA[nats]]></category><category><![CDATA[NATSio]]></category><category><![CDATA[event-driven-architecture]]></category><category><![CDATA[messaging]]></category><category><![CDATA[C#]]></category><category><![CDATA[PubSub]]></category><dc:creator><![CDATA[Joshua Steward]]></dc:creator><pubDate>Fri, 23 May 2025 04:40:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1746719245070/00318879-e7a7-48e0-b687-326f9af0c72e.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-beginning-with-nats">Beginning with NATS</h1>
<p>In the world of distributed systems, event driven architecture, EDA, has emerged as a powerful paradigm for building scalable and resilient applications. At the heart of many EDA implementations lies a robust messaging system, and NATS is a compelling choice known for its speed, simplicity, and reliability.</p>
<p>In a crowded landscape of message brokers and event buses like Kafka, Event Hub, SQS, etc. NATS carves a unique niche by focusing on fundamental application connectivity. While offering straightforward, location transparent Pub/Sub as a core capability, NATS goes beyond simple message passing. It provides a versatile foundation for implementing complex messaging patterns, including basic Fan-Out/In, Work Queues, Request/Reply semantics, and much more. This flexibility allows us to rethink traditional communication methods, offering an elegant and often simpler alternative to REST based APIs and traditional complex ingress, and this is just scratching the surface of Core NATS before delving into its advanced features like JetStream persistence and other higher-level abstractions.</p>
<h1 id="heading-where-do-we-start">Where do we start?</h1>
<p>Today, we'll explore how to integrate NATS Core into your .NET applications using C#. We'll walk through the process of setting up a console application, configuring the NATS connection using dependency injection, and then demonstrate the foundational patterns of Pub/Sub and Request/Reply.</p>
<p>We’re going to accomplish three main goals:</p>
<ol>
<li><p>Stand up a C# console project with our NuGet dependencies</p>
</li>
<li><p>Integrate with the NATS server via the C# NATS client</p>
</li>
<li><p>Demo Pub/Sub and Request/Reply</p>
</li>
</ol>
<hr />
<h1 id="heading-setting-up-your-net-console-project">Setting Up Your .NET Console Project</h1>
<p>First things first, let's create a new .NET console application. Open your terminal or command prompt and execute the following command</p>
<pre><code class="lang-powershell">dotnet new console <span class="hljs-literal">-n</span> NATSUnleashed.CSharpIntro
</code></pre>
<p>Next, we’ll need to add the official <a target="_blank" href="https://github.com/nats-io/nats.net#">NATS.NET client library</a> to our project along with the serializer package and usual hosting components. Run these commands</p>
<pre><code class="lang-powershell">dotnet add package NATS.Client.Core
dotnet add package NATS.Client.Serializers.Json
dotnet add package Microsoft.Extensions.Hosting
</code></pre>
<p>Finally, open the solution and we’ll get started!</p>
<hr />
<h1 id="heading-creating-the-natsservice">Creating the <code>NatsService</code></h1>
<p>We want a NATS service that will allow us to run our app as any of the following actors:</p>
<ul>
<li><p><code>publisher</code> - Publishes to NATS Server on a given subject</p>
</li>
<li><p><code>subscriber</code> - Subscribes to the same subject as the <code>publisher</code></p>
</li>
<li><p><code>requestor</code> - Makes requests to NATS server and expects a reply</p>
</li>
<li><p><code>responder</code> - Responds to requests from the <code>requestor</code></p>
</li>
</ul>
<h2 id="heading-natsservice-config-options-message-schema-extensions"><code>NatsService</code> - Config Options, Message Schema, Extensions</h2>
<h3 id="heading-configuration">Configuration</h3>
<p>First, we’ll create an options record to bind various configuration settings to.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">sealed</span> <span class="hljs-keyword">record</span> <span class="hljs-title">NatsConfig</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> NatsUrl { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; } = <span class="hljs-keyword">default</span>!;
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> AppType { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; } = <span class="hljs-keyword">default</span>!;
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Subject { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; } = <span class="hljs-keyword">default</span>!;
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span>? QueueGroup { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; } = <span class="hljs-keyword">default</span>!;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Deconstruct</span>(<span class="hljs-params">
        <span class="hljs-keyword">out</span> <span class="hljs-keyword">string</span> natsUrl,
        <span class="hljs-keyword">out</span> <span class="hljs-keyword">string</span> appType,
        <span class="hljs-keyword">out</span> <span class="hljs-keyword">string</span> subject,
        <span class="hljs-keyword">out</span> <span class="hljs-keyword">string</span>? queueGroup</span>)</span>
        =&gt; (natsUrl, appType, subject, queueGroup) = (NatsUrl, AppType, Subject, QueueGroup);
}
</code></pre>
<p>Simply a <code>record</code> that captures the server URL, the type of actor to run, our subject and queue group.</p>
<h3 id="heading-message-schema">Message Schema</h3>
<p>Next, a simple message schema to pass around</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">sealed</span> record <span class="hljs-title">ExampleMessage</span>(<span class="hljs-params">
    <span class="hljs-keyword">int</span> Id,
    <span class="hljs-keyword">string</span> Message</span>)</span>;
</code></pre>
<h3 id="heading-extensions-message-builders">Extensions - Message Builders</h3>
<p>Finally, a set of helpers to build messages with distinct random Id’s and static content</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Extensions</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> ExampleMessage <span class="hljs-title">NextPubSubMessage</span>(<span class="hljs-params">
        <span class="hljs-keyword">this</span> Random random</span>)</span>
        =&gt; <span class="hljs-keyword">new</span>(random.Next(<span class="hljs-number">100</span>, <span class="hljs-number">199</span>), <span class="hljs-string">"Hello World"</span>);

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> ExampleMessage <span class="hljs-title">NextRequestMessage</span>(<span class="hljs-params">
        <span class="hljs-keyword">this</span> Random random</span>)</span>
        =&gt; <span class="hljs-keyword">new</span>(random.Next(<span class="hljs-number">200</span>, <span class="hljs-number">299</span>), <span class="hljs-string">"Anyone Home?"</span>);

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> ExampleMessage <span class="hljs-title">NextReplyMessage</span>(<span class="hljs-params">
        <span class="hljs-keyword">this</span> Random random</span>)</span>
        =&gt; <span class="hljs-keyword">new</span>(random.Next(<span class="hljs-number">300</span>, <span class="hljs-number">399</span>), <span class="hljs-string">"I'm home!"</span>);
}
</code></pre>
<p>With the basics in place, we can implement the core <code>NatsService</code></p>
<h2 id="heading-natsservice-the-background-service"><code>NatsService</code> - The Background Service</h2>
<p>Our <code>NatsService</code> will be a <code>BackgroundService</code> that becomes configured as any one of our actor variations. We’ll switch on the <code>AppType</code> config to drive our behavior</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">sealed</span> class <span class="hljs-title">NatsService</span>(<span class="hljs-params">
    ILogger&lt;NatsService&gt; logger,
    INatsConnection connection,
    IOptions&lt;NatsConfig&gt; options</span>)
    : BackgroundService</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ILogger&lt;NatsService&gt; _logger = logger;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> INatsConnection _connection = connection;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IOptions&lt;NatsConfig&gt; _options = options;

    <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">override</span> Task <span class="hljs-title">ExecuteAsync</span>(<span class="hljs-params">CancellationToken stoppingToken</span>)</span>
        =&gt; _options.Value.AppType <span class="hljs-keyword">switch</span>
        {
            AppBuilding.Publisher =&gt; PublisherAsync(stoppingToken),
            AppBuilding.Subscriber =&gt; SubscriberAsync(stoppingToken),
            AppBuilding.Requestor =&gt; RequestorAsync(stoppingToken),
            AppBuilding.Responder =&gt; ResponderAsync(stoppingToken),
            _ =&gt; <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> NotSupportedException(<span class="hljs-string">$"App type <span class="hljs-subst">{_options.Value.AppType}</span> is not supported."</span>)
        };
}
</code></pre>
<p>Then we can implement each behavior variation.</p>
<h3 id="heading-publishing">Publishing</h3>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">PublisherAsync</span>(<span class="hljs-params">CancellationToken cancelToken</span>)</span>
{
    <span class="hljs-keyword">var</span> (_, _, subject, _) = _options.Value;
    _logger.LogInformation(<span class="hljs-string">"Publishing to {Subject}"</span>, subject);
    <span class="hljs-keyword">while</span> (!cancelToken.IsCancellationRequested)
    {
        <span class="hljs-keyword">var</span> message = Random.Shared.NextPubSubMessage();
        <span class="hljs-keyword">await</span> _connection.PublishAsync(
            subject, 
            message, 
            cancellationToken: cancelToken);

        <span class="hljs-keyword">await</span> Task.Delay(TimeSpan.FromSeconds(<span class="hljs-number">3</span>), cancelToken);
    }
}
</code></pre>
<h3 id="heading-subscribing">Subscribing</h3>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">SubscriberAsync</span>(<span class="hljs-params">CancellationToken cancelToken</span>)</span>
{
    <span class="hljs-keyword">var</span> (_, _, subject, <span class="hljs-keyword">group</span>) = _options.Value;
    _logger.LogInformation(<span class="hljs-string">"Subscribing to {Subject}"</span>, subject);
    <span class="hljs-keyword">await</span> <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> msg <span class="hljs-keyword">in</span> _connection.SubscribeAsync&lt;ExampleMessage&gt;(
        subject,
        queueGroup: <span class="hljs-keyword">group</span>,
        cancellationToken: cancelToken))
        _logger.LogInformation(<span class="hljs-string">"Pub/Sub - Received [{Message}]"</span>, msg.Data);
}
</code></pre>
<h3 id="heading-requesting">Requesting</h3>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">RequestorAsync</span>(<span class="hljs-params">CancellationToken cancelToken</span>)</span>
{
    <span class="hljs-keyword">var</span> (_, _, subject, _) = _options.Value;
    _logger.LogInformation(<span class="hljs-string">"Requesting to {Subject}"</span>, subject);
    <span class="hljs-keyword">while</span> (!cancelToken.IsCancellationRequested)
    {
        <span class="hljs-keyword">var</span> message = Random.Shared.NextRequestMessage();
        <span class="hljs-keyword">var</span> reply = <span class="hljs-keyword">await</span> _connection.RequestAsync&lt;ExampleMessage, ExampleMessage&gt;(
            subject, 
            message, 
            cancellationToken: cancelToken);
        _logger.LogInformation(<span class="hljs-string">"Req/Rep - Reply [{Reply}]"</span>, reply.Data);

        <span class="hljs-keyword">await</span> Task.Delay(TimeSpan.FromSeconds(<span class="hljs-number">3</span>), cancelToken);
    }
}
</code></pre>
<h3 id="heading-responding">Responding</h3>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">ResponderAsync</span>(<span class="hljs-params">CancellationToken cancelToken</span>)</span>
{
    <span class="hljs-keyword">var</span> (_, _, subject, _) = _options.Value;
    _logger.LogInformation(<span class="hljs-string">"Subscribing to {Subject}"</span>, subject);
    <span class="hljs-keyword">await</span> <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> msg <span class="hljs-keyword">in</span> _connection.SubscribeAsync&lt;ExampleMessage&gt;(
        subject, 
        cancellationToken: cancelToken))
    {
        _logger.LogInformation(<span class="hljs-string">"Req/Rep - Request [{Message}]"</span>, msg.Data);
        <span class="hljs-keyword">var</span> message = Random.Shared.NextReplyMessage();
        <span class="hljs-keyword">await</span> msg.ReplyAsync(message, cancellationToken: cancelToken);
    }
}
</code></pre>
<h2 id="heading-dependency-injection">Dependency Injection</h2>
<p>Now we’ll wire up our DI, to include our options config, the <code>NatsConnection</code> and <code>NatsService</code></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title">AppBuilding</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">const</span> <span class="hljs-keyword">string</span> Publisher = <span class="hljs-string">"publisher"</span>;
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">const</span> <span class="hljs-keyword">string</span> Subscriber = <span class="hljs-string">"subscriber"</span>;
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">const</span> <span class="hljs-keyword">string</span> Requestor = <span class="hljs-string">"requestor"</span>;
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">const</span> <span class="hljs-keyword">string</span> Responder = <span class="hljs-string">"responder"</span>;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> IServiceCollection <span class="hljs-title">AddNatsServices</span>(<span class="hljs-params">
        <span class="hljs-keyword">this</span> IServiceCollection services,
        IConfiguration config</span>)</span>
    {
        services.Configure&lt;NatsConfig&gt;(opts =&gt;
        {
            opts.AppType = config[<span class="hljs-string">"app-type"</span>] ?? <span class="hljs-string">"publisher"</span>;
            opts.NatsUrl = config[<span class="hljs-string">"nats:url"</span>] ?? <span class="hljs-string">"nats://localhost:4222"</span>;            
            opts.Subject = config[<span class="hljs-string">"nats:subject"</span>] ?? <span class="hljs-string">"some.subject"</span>;
            opts.QueueGroup = config[<span class="hljs-string">"nats:group"</span>];
        });
        services.TryAddSingleton&lt;INatsConnection&gt;(sp =&gt;
        {
            <span class="hljs-keyword">var</span> config = sp.GetRequiredService&lt;IOptions&lt;NatsConfig&gt;&gt;().Value;
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> NatsConnection(<span class="hljs-keyword">new</span>()
            {
                Url = config.NatsUrl,
                SerializerRegistry = NatsJsonSerializerRegistry.Default
            });
        });
        <span class="hljs-keyword">return</span> services.AddHostedService&lt;NatsService&gt;();
    }
}
</code></pre>
<h2 id="heading-program-main">Program: Main</h2>
<p>And finally, of course, our generic main to kick off the <code>Host</code></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> Microsoft.Extensions.Hosting;
<span class="hljs-keyword">using</span> NATSUnleashed.CSharpIntro;

<span class="hljs-keyword">var</span> builder = Host.CreateApplicationBuilder(args);
builder.Services.AddNatsServices(builder.Configuration);

<span class="hljs-keyword">var</span> app = builder.Build();

<span class="hljs-keyword">await</span> app.RunAsync();
</code></pre>
<p>Excellent, at this stage our app is ready to build and then demo. Let’s kickoff the build quick</p>
<pre><code class="lang-powershell">dotnet build <span class="hljs-literal">-c</span> Release
</code></pre>
<p>and we should see success similar to this</p>
<pre><code class="lang-powershell">Restore complete (<span class="hljs-number">0.3</span>s)
  NATSUnleashed.CSharpIntro succeeded (<span class="hljs-number">0.3</span>s) → bin\Release\net9.<span class="hljs-number">0</span>\NATSUnleashed.CSharpIntro.dll

Build succeeded <span class="hljs-keyword">in</span> <span class="hljs-number">1.0</span>s
</code></pre>
<hr />
<h1 id="heading-running-nats-server-with-docker">Running NATS Server with Docker</h1>
<p>Before we demo, we need a NATS server running. Just as we did in <a target="_blank" href="https://concurrentflows.com/getting-started-with-nats-cli">Getting Started with NATS CLI</a> we’ll start up NATS server using Docker. Docker provides a convenient way to do this. If you don't have Docker installed, you'll need to install it from the official Docker website.</p>
<p>From a new terminal execute the following command</p>
<pre><code class="lang-powershell">docker run -<span class="hljs-literal">-rm</span> -<span class="hljs-literal">-name</span> my<span class="hljs-literal">-nats</span> <span class="hljs-literal">-p</span> <span class="hljs-string">"4222:4222"</span> <span class="hljs-literal">-p</span> <span class="hljs-string">"8222:8222"</span> nats <span class="hljs-literal">-n</span> nats1 <span class="hljs-literal">-m</span> <span class="hljs-number">8222</span>
</code></pre>
<p>This command is the same as before and breaks down into a few key pieces</p>
<ol>
<li><p>We expose the default NATS port 4222 and the default monitoring port 8222</p>
</li>
<li><p>Name the NATS server instance with <code>-n nats1</code></p>
</li>
<li><p>Enable NATS monitoring via <code>-m 8222</code></p>
</li>
</ol>
<p>You should then see an output similar to this</p>
<pre><code class="lang-powershell">[<span class="hljs-number">1</span>] [<span class="hljs-type">INF</span>] Starting nats<span class="hljs-literal">-server</span>
[<span class="hljs-number">1</span>] [<span class="hljs-type">INF</span>]   Version:  <span class="hljs-number">2.11</span>.<span class="hljs-number">1</span>
[<span class="hljs-number">1</span>] [<span class="hljs-type">INF</span>]   Git:      [<span class="hljs-type">d78523b</span>]
[<span class="hljs-number">1</span>] [<span class="hljs-type">INF</span>]   Name:     nats1
[<span class="hljs-number">1</span>] [<span class="hljs-type">INF</span>]   ID:       NBZG74EPNUPKYPVB7YFHOHABDAZ7EN3FFPHQYJUEAQODJYTZVNDMEH25
[<span class="hljs-number">1</span>] [<span class="hljs-type">INF</span>] Starting http monitor on *******:<span class="hljs-number">8222</span>
[<span class="hljs-number">1</span>] [<span class="hljs-type">INF</span>] Listening <span class="hljs-keyword">for</span> client connections on *******:<span class="hljs-number">4222</span>
[<span class="hljs-number">1</span>] [<span class="hljs-type">INF</span>] Server is ready
</code></pre>
<hr />
<h1 id="heading-demo-pubsub">Demo: Pub/Sub</h1>
<p>Demo time! Open three new consoles to <code>./bin/Release/net9.0</code> and kickoff our app</p>
<p><strong>Subscribers 2x</strong></p>
<pre><code class="lang-powershell">dotnet NATSUnleashed.CSharpIntro.dll -<span class="hljs-literal">-app</span><span class="hljs-literal">-type</span> subscriber
</code></pre>
<p><strong>Publisher</strong></p>
<pre><code class="lang-powershell">dotnet NATSUnleashed.CSharpIntro.dll -<span class="hljs-literal">-app</span><span class="hljs-literal">-type</span> publisher
</code></pre>
<p>With those running, we should see messages published and delivered to each subscriber</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1746710172355/00583964-3465-42c1-8980-22b9c31f00af.png" alt class="image--center mx-auto" /></p>
<h1 id="heading-demo-pubsub-queue-groups">Demo: Pub/Sub Queue Groups</h1>
<p>Next, we’ll see Queue Groups in action. These allow you distribute messages randomly among subscribers. Stop the Publisher and both subscribers, then restart the subscribers with this new command</p>
<pre><code class="lang-powershell">dotnet NATSUnleashed.CSharpIntro.dll -<span class="hljs-literal">-app</span><span class="hljs-literal">-type</span> subscriber -<span class="hljs-literal">-nats</span>:<span class="hljs-built_in">group</span> my<span class="hljs-literal">-queue</span><span class="hljs-literal">-group</span>
</code></pre>
<p>And start the publisher again</p>
<pre><code class="lang-powershell">dotnet NATSUnleashed.CSharpIntro.dll -<span class="hljs-literal">-app</span><span class="hljs-literal">-type</span> publisher
</code></pre>
<p>And observe the output, note each message is only delivered to a single subscriber</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1746710470918/6d704b6e-3df8-492c-ba00-1bfd5f99a686.png" alt class="image--center mx-auto" /></p>
<h1 id="heading-demo-requestreply">Demo: Request/Reply</h1>
<p>Finally, for Request/Reply, shutdown the subscribers and publisher. Then kickoff one or more responder apps</p>
<pre><code class="lang-powershell">dotnet NATSUnleashed.CSharpIntro.dll -<span class="hljs-literal">-app</span><span class="hljs-literal">-type</span> responder
</code></pre>
<p>Then kickoff the requestor app</p>
<pre><code class="lang-powershell">dotnet NATSUnleashed.CSharpIntro.dll -<span class="hljs-literal">-app</span><span class="hljs-literal">-type</span> requestor
</code></pre>
<p>And the output should be similar to this, note that only one responder is received by the requestor per request</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1746718550188/c8cc833f-0363-4114-a600-f3eb3f4e6cae.png" alt class="image--center mx-auto" /></p>
<hr />
<h1 id="heading-wrap-up">Wrap Up</h1>
<p>Today, we built a C# dotnet console app that integrated with a NATS server via the NATS.Net client. Our app could run in either Pub/Sub or Request/Reply modes, and we demonstrated that functionality. This really lays the foundation for building some really cool stuff. With just some simple configuration and the clean API design of the client library we can get up and running quickly.</p>
<p>Until next time! All code is available at <a target="_blank" href="https://github.com/ptsteward/ConcurrentFlows.HashNode/tree/master/NATSUnleashed">ConcurrentFlows GitHub</a></p>
<p>Have a specific question about NATS? Want a specific topic covered? Drop it in the comments!</p>
]]></content:encoded></item><item><title><![CDATA[NATS Subject Aware Messaging]]></title><description><![CDATA[What is a NATS Subject?
NATS is a location transparent messaging technology built around foundational Pub/Sub semantics. That means it doesn’t matter if a publisher is in one hemisphere, while a subscriber is in the opposite global hemisphere. As lon...]]></description><link>https://concurrentflows.com/nats-subject-aware-messaging</link><guid isPermaLink="true">https://concurrentflows.com/nats-subject-aware-messaging</guid><category><![CDATA[nats]]></category><category><![CDATA[event-driven-architecture]]></category><category><![CDATA[PubSub]]></category><category><![CDATA[messaging]]></category><category><![CDATA[NATSio]]></category><dc:creator><![CDATA[Joshua Steward]]></dc:creator><pubDate>Fri, 16 May 2025 11:12:12 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1745820839619/c3a4c4b1-d277-442c-8a9e-312485c8b94a.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-what-is-a-nats-subject">What is a NATS Subject?</h1>
<p>NATS is a location transparent messaging technology built around foundational Pub/Sub semantics. That means it doesn’t matter if a publisher is in one hemisphere, while a subscriber is in the opposite global hemisphere. As long as both the sending and receiving parties can connect to a NATS server, they can communicate with one another. NATS <em>Subjects</em> facilitate this communication, they are the mutual knowledge between publishers and consumers, i.e. a publisher <em>publishes to a Subject</em>, while a subscriber <em>subscribes</em> to a matching <em>Subject</em>.</p>
<p>NATS defines <em>Subjects</em> as a specifically formatted string consisting of <em>Tokens</em> separated by a <code>.</code> (dot), for instance</p>
<pre><code class="lang-plaintext">{token1}.{token2}.{tokenN}
market.data.stock.AAPL
market.data.forex.EURUSD
trade.order.submitted
trade.order.executed
</code></pre>
<p>These <em>Subjects</em> are just simple strings, and are by default ephemeral, but they create an expressive, powerful, addressing mechanism. You can think of <em>Subjects</em> as an address on an envelope, it captures in detail, the single destination the message is <em>sent</em>.</p>
<p>The <em>Tokens</em> form a hierarchy, category, and uniqueness of every publication destination, in the same way Country, State/Provence, City, Postal Code, uniquely define a postal destination. If you’re picking up on the foreshadowing here’s the reveal, the <em>Subject</em> doesn’t fully define the ultimate <em>Delivery/Consumption</em> of the message. In much the same way as a letter could be opened and read by one or many recipients, NATS messages published into a given <em>Subject</em> are delivered in a variety of ways. They can be transformed into entirely new subjects, delivered to specific subscribers in a <em>Queue Group,</em> or consumed by subscribers to a <em>Wildcard Subject</em>, i.e. <code>market.data.stock.*</code> Collectively this is the concept of <em>Subject Awareness.</em></p>
<hr />
<h1 id="heading-subject-awareness">Subject Awareness</h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1746722944508/e04bcdc4-e188-472f-a1e5-a0d84e30e73b.png" alt class="image--center mx-auto" /></p>
<p>Subject Awareness refers to the way messages are routed and consumed based on the <em>Subject</em> of a message. Subject awareness allows some powerful expression. We can leverage the dynamic nature of <em>Subjects</em> to build relevant intelligence into applications based on the <em>Subject’s</em> content and structure. For instance:</p>
<ol>
<li><p><strong>Intelligent Consumption:</strong> Specifically subscribe to content of interest, i.e. <code>market.data.stock.AAPL</code> while ignoring <code>market.data.forex.&gt;</code>, only messages related to <code>APPL</code> stock will be received, anything under the scope of <code>forex</code> is ignored</p>
</li>
<li><p><strong>Contextual Communication:</strong> The <em>Subject</em> provides valuable context regarding the message content, purpose, etc. <code>user.status.online</code> indicates that a ‘User’ has become ‘Online’, <code>sensor.humidity.kitchen</code> immediately indicates the subscriber is receiving a ‘Humidity Sensor’ reading, from the ‘Kitchen’</p>
</li>
<li><p><strong>Malleable Evolution:</strong> Unlike configuring some rigid topic/queue constructs upfront, <em>Subjects</em> are ephemeral by default and can be dynamically created, while <em>Wildcard</em> subscribers can be delivered messages from new unique <em>Subjects</em> without modification, i.e. subscribers to <code>cluster.apps.*.status</code> would receive ‘Status’ messages from all existing and new ‘Apps’ without modification</p>
</li>
</ol>
<h2 id="heading-publishing-vs-subscribing">Publishing vs Subscribing</h2>
<p>When a NATS Publisher sends a message, it assigns a <em>Subject</em> describing the context of the message. This context can specify content type or category, e.g. <code>app.status</code>, would be an App Status message. The <em>Subject</em> could contain the origin of the message, e.g. <code>products.factory.east123</code>, is a message from factory East 123. Even purpose can be defined, e.g. <code>records.123.delete</code>, Delete the entity with id: 123.</p>
<p>Subscribers on the other end express an interest in <em>Subjects</em> the same way a researcher might be interested in a given domain. That interest may be very specific, e.g. <code>cluster.east.app.chat-app.user.user1</code>, matching a specific user, of a specific app, in a specific cluster. Alternatively, it could be very broad, matching many individual <em>Subjects</em>, e.g. <code>cluster.east.&gt;</code>, matching all <em>Subjects</em> within the scope of a specific cluster.</p>
<p>It’s important to make clear, a message will be published to a <em>single specific Subject</em>. This means a message published to <code>market.data.stock.AAPL</code> would not be received via a subscription to <code>market.data.stock</code>, or <code>market.data.stock.APPL.average</code>. Only a subscription pattern matching the published <em>Subject</em> will receive the message, e.g. <code>market.data.stock.AAPL</code>, <code>market.data.stock.*</code>, <code>market.data.&gt;</code>, etc.</p>
<hr />
<h1 id="heading-the-subject-hierarchy">The Subject Hierarchy</h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745815381129/c4076555-36dc-49bc-ad92-80927b9ece1e.png" alt class="image--center mx-auto" /></p>
<p><em>Subjects</em> in NATS are formed by a collection of dot separated <em>Tokens.</em> Each <em>Token</em> represents a level in a <em>Subject</em> hierarchy that collectively describes the <em>Subject</em> space of a particular domain.</p>
<p>Let’s explore an example to understand why hierarchy design can be important. If we wanted to describe an Order Service’s <em>Subject</em> space, we could first define the following <em>Subject</em> template, generally following the broad to specific rule of thumb:</p>
<ul>
<li><code>orders.status.{status}.order.{id}</code></li>
</ul>
<p>This would form something like the following hierarchy</p>
<ul>
<li><p><code>orders.status.created.order.{id}</code></p>
</li>
<li><p><code>orders.status.confirmed.order.{id}</code></p>
</li>
<li><p><code>orders.status.shipped.order.{id}</code></p>
</li>
<li><p><code>orders.status.delivered.order.{id}</code></p>
</li>
</ul>
<p>This hierarchy effectively categorizes ‘Status’ by deliberately making that a constant level of the hierarchy. Also, the target entity Order is a static hierarchy level, the final one, with the specific Order Id following. Subscribers can express interest in a specific Status but all Order Id’s with the wildcard asterisk*, i.e. <code>orders.status.created.order.*</code> would receive all Created Orders. Alternatively, an interest in <em>all</em> Statuses can be expressed with an asterisk, i.e. <code>orders.status.*.order.*</code>. The contextual meaning of the asterisk remains clear with the context of the preceding <em>Token,</em> i.e. Status, or Order.</p>
<p>Further, if our Orders domain needs extension beyond Status and starts publishing a new category, we can add it without breaking existing subscriptions:</p>
<ul>
<li><code>orders.shipment.{stage}.order.{id}</code></li>
</ul>
<p>Conceptually, <em>Subjects</em> in the new template exist somewhere between and among three higher-level Statuses</p>
<ul>
<li><p><code>orders.status.confirmed.order.{id}</code></p>
</li>
<li><p><code>orders.status.shipped.order.{id}</code></p>
</li>
<li><p><code>orders.status.delivered.order.{id}</code></p>
</li>
</ul>
<p>But our earlier subscriptions, <code>orders.status.*.order.*</code>, etc. still only target the intended Status messages. To express interest in Shipment Stages, we can subscribe to <code>orders.shipment.staged.order.*</code>, <code>orders.shipment.in-transit.order.*</code>, <code>orders.shipment.*.order.*</code>, etc.</p>
<hr />
<h1 id="heading-subjects-as-expressive-keys">Subjects as Expressive Keys</h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1746250156882/d222fe75-e464-40cc-b88d-5a971ac22156.png" alt class="image--center mx-auto" /></p>
<p>Many messaging technologies make heavy use of <em>Message Keys</em>, these typically uniquely identify a particular categorization of the message or its content. A Topic representing car dealership inventory might use the Make as a message key, e.g. Ford, Toyota, Chevy, etc. It might not make much sense to use something like the Vin of each vehicle as a message key, given each is generally unique. The salient point is that the <em>Cardinality</em> of the key is a critical factor in message key selection.</p>
<p><em>Cardinality</em> of the message key becomes so critical because it will typically drive message routing, its final partition and the ordering, even compaction, of related messages. If I needed all updates to my Ford inventory applied in the correct order, with something like Kafka, all updates would need to be in the same partition. Additionally, if my consuming process duration and message volume dictates the need for 100 consumers in a group, yet the cardinality of my message key is much less, the resulting partition distribution and consumer group balance is far from ideal.</p>
<p>NATS again takes a different approach. All messages are virtually keyless, consisting of only the destination <em>Subject</em> and payload, with optional headers and/or a reply subject. <em>Subjects</em>, as far as the NATS server is considered, are a single unit to which to deliver messages. It cannot, itself, be divided into <em>partitions,</em> only deeper layers of the hierarchy added to divide the <em>Subject</em> space.</p>
<p>Thanks to this, and the expressive hierarchy, a NATS message can uniquely identify many categorizations or identities of a message completely decoupled from consumption. The cardinality of the <em>Subject</em> has little role in subscriber distribution, or, to a degree, the proper ordering of related messages.</p>
<p>Where in the Kafka example my <em>Key</em> might be Ford, and that dictates its final partition and consequently its assigned consumer. The NATS message might have the <em>Subject</em> <code>inventory.update.{make}.{model}.{year}</code> and the subscribing group would express interest in <code>inventory.update.Ford.&gt;</code> and within a Queue Group of 100 subscribers the message volume would be evenly distributed.</p>
<hr />
<h1 id="heading-consumption-superpower-subjects-vs-topics">Consumption Superpower: Subjects vs Topics</h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1746250118778/d7998782-36f4-46f1-aced-2b72a1093747.png" alt class="image--center mx-auto" /></p>
<p>The real expressive power of <em>Subjects</em> can be seen in the way we consume them and how that differs from something like a Kafka Topic. A Kafka Topic represents a single category of message(s) and their associated type(s). A Kafka Topic like <code>factory1-machine-status</code> would reasonably be expected to provide a stream of Machine Status updates from Factory 1. Likely we would key this Topic on something like <code>MachineId</code>. If we only care about a single Status, say <code>Faulted</code>, the client side consumer would need to do that filtering, still receiving all messages yet discarding most. Additionally, another Factory, say <code>factory2</code>, would be an entirely separate and discrete Topic.</p>
<p>The <em>Subject</em> in NATS however can represent and yield the entire <em>Domain Structure</em> however the engineer sees fit. With a <em>Subject</em> template like <code>{factory}.{id}.{area}.{id}.{machine}.{id}.status.{status}</code> we could express a subscription like the previous example with <code>factory.*.area.*.machine.*.status.*</code>. More importantly we can express the exact consumer interest that’s relevant. With a Topic of <code>factory1-machine-status</code>, both producer and consumers are constrained and coupled to all Statuses, all Machines, at Factory 1. The <em>Subject</em> hierarchy, however, decouples the <em>intent</em> of publishers from the <em>interest</em> of subscribers.</p>
<p>We could have a single publisher handling all Machines and a single Status: Nominal, Degraded, Faulted, etc. And on the other end have a single subscriber per Machine and all Statuses, or <code>factory.1.area.1.machine.1.status.*</code>, <code>factory.1.area.1.machine.2.status.*</code>, etc. Going a step further, we could also have a publisher sending general state updates for a Factory Area within the same <em>Subject</em> space, i.e. published to <code>factory.1.area.{id}</code><em>.</em> These could be simply describing the details of the Factory Area, e.g. name, number of units, geofence, etc. What’s powerful is that this entire <em>Subject</em> space can then be ingested by a JetStream Stream and persisted as a single consistent unit. The Stream would subscribe to <code>factory.*.area.*.machine.*.status.*</code>, and consumers could view into any slice of this space necessary, e.g. <code>factory.*.area.*</code> - for general Area updates at all Factories, <code>factory.1.area.*.machine.*</code> - for updates from Factory 1, all Areas and all Machines, etc. The immense flexibility can be hard to get used to but with a proper hierarchy, filters and wildcards, you can express some very complex queries quite simply.</p>
<hr />
<h1 id="heading-wrap-up">Wrap Up</h1>
<p>A well formed <em>Subject</em> hierarchy is a complex topic with many areas for exploration. Hopefully, this at least gets you thinking in broader terms than the strict categorization of a Topic and excited to explore the malleable world of <em>Subject Aware Messaging.</em></p>
<p>Recapping, we explored the concept of a NATS <em>Subject,</em> including publishing specificity and expressing subscriber interest. We reoriented message routing around addressing, categorizing, and keying messages into the malleable and descriptive nature of hierarchal <em>Subjects.</em> We also looked at the decoupling of publisher intent from subscriber interest, leveraging the <em>Subject</em> space to describe a broad domain while subscribers stay well scoped. It should be clear now, in the NATS world a well thought out and planned <em>Subject</em> hierarchy and template is a critical design decision but one that can evolve with your domain’s needs.</p>
<p>Have a specific question about NATS? Want a specific topic covered? Drop it in the comments!</p>
]]></content:encoded></item><item><title><![CDATA[Getting Started with NATS CLI]]></title><description><![CDATA[What is NATS?
The technology landscape is full of message brokers and event/message buses: Kafka, Event Hub, Pulsar, SQS, Google Pub/Sub, and more in no particular order. In this crowded space, NATS stands out as a unique perspective of the connectiv...]]></description><link>https://concurrentflows.com/getting-started-with-nats-cli</link><guid isPermaLink="true">https://concurrentflows.com/getting-started-with-nats-cli</guid><category><![CDATA[event-driven-architecture]]></category><category><![CDATA[PubSub]]></category><category><![CDATA[messaging]]></category><category><![CDATA[nats]]></category><category><![CDATA[NATSio]]></category><dc:creator><![CDATA[Joshua Steward]]></dc:creator><pubDate>Fri, 09 May 2025 03:41:25 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1745701548141/851d184a-e332-4d4e-a684-f53fe74f9f94.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-what-is-nats">What is NATS?</h1>
<p>The technology landscape is full of <em>message brokers</em> and <em>event/message buses</em>: Kafka, Event Hub, Pulsar, SQS, Google Pub/Sub, and more in no particular order. In this crowded space, NATS stands out as a unique perspective of the connectivity problem space. Beyond simply passing messages around, NATS is oriented toward solving application connectivity from a first principles like foundation.</p>
<p>At first glance, NATS is a message bus, it facilitates location transparent Pub/Sub. But upon that, so much more can be built, and complex, nuanced patterns can be expressed. Basic Fan-Out/In Pub/Sub, Work Queue Distribution, Request/Reply semantics, Weighted &amp; Mapped Routing, etc. Capabilities like this allow us a new way to approach the connectivity problem space. When we might traditionally reach for HTTP REST, or complex load balanced ingress, NATS provides an elegant alternative. And this is just with Core NATS before we dig into JetStream persistence, Key-Value Semantics, Object Storage, NEX Workloads, etc.</p>
<h1 id="heading-where-do-we-start">Where do we start?</h1>
<p>In this introduction we’re going to accomplish three main objectives:</p>
<ol>
<li><p>Install our tooling and stand up a NATS server</p>
</li>
<li><p>Pub/Sub messages using <em>Subject</em> based addressing</p>
</li>
<li><p>Execute Request/Reply built on top of Pub/Sub</p>
</li>
</ol>
<hr />
<h1 id="heading-tooling">Tooling</h1>
<h2 id="heading-nats-cli">NATS CLI</h2>
<p>First, install the <a target="_blank" href="https://docs.nats.io/using-nats/nats-tools/nats_cli">NATS CLI tool</a>, this is the unified tool to interact with the NATS server. From the CLI we can Pub/Sub, Request/Reply, manage Streams, Benchmark, etc. The tool can be installed a variety of ways as documented in the <a target="_blank" href="https://github.com/nats-io/natscli?tab=readme-ov-file#installation">GitHub README</a> and the binaries are available in <a target="_blank" href="https://github.com/nats-io/natscli/releases">GitHub Releases</a>. For instance, you can leverage <code>go</code> and install the latest with</p>
<pre><code class="lang-powershell">go install github.com/nats<span class="hljs-literal">-io</span>/natscli/nats@latest
</code></pre>
<p>Ensure <code>NATS</code> has been added to your <code>$PATH</code> and with the following you should see the latest version you have</p>
<pre><code class="lang-powershell">nats -<span class="hljs-literal">-version</span>
<span class="hljs-number">0.2</span>.<span class="hljs-number">2</span>
</code></pre>
<p>Conveniently, in addition to the typical <code>-h, --help</code> the CLI gives a selection of “cheat sheets” via <code>nats cheat {cheat}</code>. Looking through these will really help understanding how to work with the tool and what can be done with it.</p>
<pre><code class="lang-powershell">nats cheat
Available Cheats:
    account
    auth
    bench
    consumer
    contexts
    errors
    events
    kv
    latency
    obj
    pub
    reply
    schemas
    server
    stream
    sub
</code></pre>
<h2 id="heading-nats-server">NATS Server</h2>
<p>Next, you’ll need the <code>nats-server</code>, this is the core of it all and a single feature packed binary. The binary itself can be <a target="_blank" href="https://nats.io/download/">downloaded via NATS.io</a>, alternatively <code>nats-server</code> can be easily spun up in Docker/Podman. Here, I’ll use Docker and we’re going to configure a couple of items.</p>
<ol>
<li><p>We’ll expose the default NATS port 4222 and the default monitoring port 8222</p>
</li>
<li><p>Name the NATS server instance with <code>-n nats1</code></p>
</li>
<li><p>Enable NATS monitoring via <code>-m 8222</code></p>
</li>
</ol>
<pre><code class="lang-powershell">docker run -<span class="hljs-literal">-rm</span> -<span class="hljs-literal">-name</span> my<span class="hljs-literal">-nats</span> <span class="hljs-literal">-p</span> <span class="hljs-string">"4222:4222"</span> <span class="hljs-literal">-p</span> <span class="hljs-string">"8222:8222"</span> nats <span class="hljs-literal">-n</span> nats1 <span class="hljs-literal">-m</span> <span class="hljs-number">8222</span>
</code></pre>
<pre><code class="lang-powershell">[<span class="hljs-number">1</span>] [<span class="hljs-type">INF</span>] Starting nats<span class="hljs-literal">-server</span>
[<span class="hljs-number">1</span>] [<span class="hljs-type">INF</span>]   Version:  <span class="hljs-number">2.11</span>.<span class="hljs-number">1</span>
[<span class="hljs-number">1</span>] [<span class="hljs-type">INF</span>]   Git:      [<span class="hljs-type">d78523b</span>]
[<span class="hljs-number">1</span>] [<span class="hljs-type">INF</span>]   Name:     nats1
[<span class="hljs-number">1</span>] [<span class="hljs-type">INF</span>]   ID:       ND6JF5FBLCHPSUBLSAJRLSHWANFQ2D6RJWSK3XJDFBIX5RTE3NQDH5ER
[<span class="hljs-number">1</span>] [<span class="hljs-type">INF</span>] Starting http monitor on *******:<span class="hljs-number">8222</span>
[<span class="hljs-number">1</span>] [<span class="hljs-type">INF</span>] Listening <span class="hljs-keyword">for</span> client connections on *******:<span class="hljs-number">4222</span>
[<span class="hljs-number">1</span>] [<span class="hljs-type">INF</span>] Server is ready
</code></pre>
<hr />
<h1 id="heading-pubsub-nats-cli">Pub/Sub - NATS CLI</h1>
<p>With our NATS server running, let’s begin with the simplest expression of NATS, Pub/Sub. Open three new terminals, two for subscription and one for publishing.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1746761731693/28bd1951-fb68-4fef-9b66-0c5ec8570ee9.png" alt class="image--center mx-auto" /></p>
<p>Next, separately begin two subscriptions with <code>nats sub</code></p>
<pre><code class="lang-powershell">nats sub some.subject
</code></pre>
<p>Executing this in both subscription terminals should yield some like this</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1746761748747/f1a15b64-ee4f-4498-a607-a710515a15e5.png" alt class="image--center mx-auto" /></p>
<p>Finally, let’s publish a message with <code>nats pub</code> and see it delivered to both subscribers.</p>
<p>From the <strong>NATS Pub</strong> terminal execute</p>
<pre><code class="lang-powershell">nats pub some.subject <span class="hljs-string">"Hello World"</span>
</code></pre>
<p>Altogether, we should see the message published and received by both subscribers</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1746680596509/7b616cf1-8402-4479-b49a-6d8879f73bd6.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-adding-headers">Adding Headers</h2>
<p>Just for fun, let’s add a <em>Header</em> to our message, similar to HTTP Headers, these are Key/Value pairs that support multiple values. These can be used to pass metadata, or as we get more advanced can enable deduplication, optimistic concurrency, etc.</p>
<p>Execute the following <code>nats pub</code> command, passing a generic <code>Content-Type</code> header</p>
<pre><code class="lang-powershell">nats pub some.subject -<span class="hljs-literal">-header</span> <span class="hljs-string">"Content-Type:text/plain"</span> <span class="hljs-string">"Hello World"</span>
</code></pre>
<p>Altogether we should see the new output</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1746680709883/ff850b51-ef6b-47aa-b669-30fd140bdbb5.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-using-queue-groups">Using Queue Groups</h2>
<p>Previously, the published message was delivered to <em>all</em> subscribers, i.e. if we had 100 subscribers, every one would receive the message. However, sometimes we want to distribute messages to a group of subscribers. This is similar to the concept of a work queue, where each message is handled by one and only one subscriber.</p>
<p>To express this pattern in NATS we use a <em>Queue Group</em>. Defined on the subscription, all subscribers within the same group will share responsibility for a subject. NATS will deliver each message to one subscriber in via a nearly random selection that tends towards an even distribution.</p>
<p>Seeing it action, start two new subscriptions with the following command</p>
<pre><code class="lang-powershell">nats sub some.subject -<span class="hljs-literal">-queue</span> my_group
</code></pre>
<p>Then we can publish again</p>
<pre><code class="lang-powershell">nats pub some.subject <span class="hljs-string">"Hello World"</span>
</code></pre>
<p>And in result we should see that only one subscriber received the message</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1746680808160/db71e266-8acf-4cb3-9a62-ac2d6b5a2b10.png" alt class="image--center mx-auto" /></p>
<p>Note though, subscriptions outside the <em>Queue Group</em> and in other groups, are still delivered the message</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1746680905958/a262df2c-cab0-4cce-87dc-dda5ee90c1c5.png" alt class="image--center mx-auto" /></p>
<h1 id="heading-requestreply-nats-cli">Request/Reply - NATS CLI</h1>
<p>Another common communication pattern is Request/Reply, where we expect a single reply for a given request. While this pattern is engrained within something like an HTTP call, NATS expresses this pattern from the basis of Pub/Sub. A <em>Request</em> is published while a temporary <em>Inbox</em> is formed and subscribed to by the “Requestor”, any subscriber can then <em>Reply</em> to the <em>Request</em> on the provided <em>Inbox</em> subject.</p>
<p>Let’s see it in action! First, open a new terminal and stand up a “Responder” to <em>Requests</em></p>
<pre><code class="lang-powershell">nats reply some.subject <span class="hljs-string">"Responded @ {{Time}}"</span>
</code></pre>
<p>Then, from our <strong>NATS Pub</strong> terminal issue the <em>Request</em></p>
<pre><code class="lang-powershell">nats request some.subject <span class="hljs-string">"Hello World"</span>
</code></pre>
<p>And we should see the <em>Reply</em> returned back to our requestor as expected</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1746681049027/5c831573-9b59-46b3-b134-7db8e448022c.png" alt class="image--center mx-auto" /></p>
<p>We’ll discuss this deeper when we code a Request/Reply pattern, but this illustrates the basic concept. Also note, that we published on the same <em>Subject</em> as before, our earlier <em>Subscribers</em> still received the new message, although they aren’t going to respond to our <em>Request</em>, still, interest in the <em>Subject</em> is respected and the message delivered.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1746681162263/71ae59f7-9154-49ca-a1ec-724af0ca0ce6.png" alt class="image--center mx-auto" /></p>
<hr />
<h1 id="heading-wrap-up">Wrap Up</h1>
<p>In this introduction we got familiar with standing up a NATS Server via Docker. Next, we got acquainted with the NATS CLI and its basic Pub/Sub, Request/Reply capabilities. With just a few commands, a single container, we’re already publishing and subscribing with location transparent and subject aware messaging. Our NATS Server, Publisher, and Subscribers can easily be globally remote from one another, and given access, could just as easily communicate. Clearly, we’re just beginning so stay tuned and we’ll keep exploring.</p>
<p>Have a specific question about NATS? Want a specific topic covered? Drop it in the comments!</p>
]]></content:encoded></item><item><title><![CDATA[Azure Service Bus: Reading Messages Using ServiceBusProcessor]]></title><description><![CDATA[Service Bus Series - Part 4
Previously, we've covered creating, authenticating, writing and testing against an Azure Service Bus. The next step on our journey is to read continuously using a ServiceBusProcessor. This component triggers event handlers...]]></description><link>https://concurrentflows.com/azure-service-bus-reading-messages-using-servicebusprocessor</link><guid isPermaLink="true">https://concurrentflows.com/azure-service-bus-reading-messages-using-servicebusprocessor</guid><category><![CDATA[Azure]]></category><category><![CDATA[Azure Service Bus]]></category><category><![CDATA[azure service bus queues]]></category><category><![CDATA[C#]]></category><category><![CDATA[dotnet]]></category><category><![CDATA[event-driven-architecture]]></category><dc:creator><![CDATA[Joshua Steward]]></dc:creator><pubDate>Tue, 21 May 2024 22:18:20 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1716304169779/8fbd1412-d425-4107-be7b-65c4bdf2f84f.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-service-bus-series-part-4">Service Bus Series - Part 4</h1>
<p>Previously, we've covered <a target="_blank" href="https://concurrentflows.com/creating-an-azure-service-bus-and-sending-a-queue-message">creating</a>, <a target="_blank" href="https://concurrentflows.com/azure-service-bus-authentication-with-entra-identities-and-azure-credentials">authenticating</a>, <a target="_blank" href="https://concurrentflows.com/azure-service-bus-authentication-with-entra-identities-and-azure-credentials">writing</a> and <a target="_blank" href="https://concurrentflows.com/azure-service-bus-integration-testing-with-xunit-and-admin-client">testing</a> against an Azure Service Bus. The next step on our journey is to read continuously using a <code>ServiceBusProcessor</code>. This component triggers event handlers and is itself very similar to a <code>BackgroundService</code>.</p>
<h1 id="heading-what-is-the-servicebusprocessor">What is the ServiceBusProcessor?</h1>
<p>The <a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/azure.messaging.servicebus.servicebusprocessor?view=azure-dotnet"><code>ServiceBusProcessor</code></a> is a high-level abstraction around a set of <code>ServiceBusReceivers</code> that allows a consumer to continuously receive messages. The processor comes in two varieties: a standard processor for Queues/Topics, and a Session enabled processor that manages the locks around Service Bus Sessions [stay tuned 🤓].</p>
<p>The processor takes a pair of event handlers: one to handle the message, and another to handle any errors thrown during handling a message. With this model of processing, each message is managed through the event args passed to each delegate: <a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/azure.messaging.servicebus.processmessageeventargs?view=azure-dotnet"><code>ProcessMessageEventArgs</code></a> and <a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/azure.messaging.servicebus.processerroreventargs?view=azure-dotnet"><code>ProcessErrorEventArgs</code></a> respectively. Through these arguments the handler can execute any of the typical <em>Receiver</em> operations, e.g. Abandon, Dead Letter, etc.</p>
<pre><code class="lang-csharp">args.AbandonMessageAsync(args.Message);
args.DeadLetterMessageAsync(args.Message);
</code></pre>
<h1 id="heading-what-well-build">What We'll Build</h1>
<p>We're going to build the core of what could become an Event-Driven microservice. This service will consume continuously from Azure Service Bus and delegate the messages to strongly typed handlers. The consuming process will be a <em>Hosted Service</em> derived from a <code>BackgroundService</code>.</p>
<h1 id="heading-why-a-background-service">Why a Background Service?</h1>
<blockquote>
<p><em>Why not just use a basic</em><code>IHostedService</code><em>implementation?</em></p>
</blockquote>
<p>Well, the key difference between an <code>IHostedService</code> and a <code>BackgroundService</code> lies in how the framework itself treats these components. A <code>BackgroundService</code> exposes a virtual nullable Task representing the execution of the <em>Hosted Service.</em> This is important because it gives the <em>Host</em> knowledge of your code's execution. Critically, the continuously running service is awaited and any exceptions are propagated out of the background to the <em>Host.</em></p>
<hr />
<h1 id="heading-project-setup">Project Setup</h1>
<p>First, dotnet new up a blank console application and install the following packages:</p>
<pre><code class="lang-apache"><span class="hljs-attribute">dotnet</span> add package Azure.Identity
<span class="hljs-attribute">dotnet</span> add package Azure.Messaging.ServiceBus
<span class="hljs-attribute">dotnet</span> add package Microsoft.Extensions.Hosting
<span class="hljs-attribute">dotnet</span> add package Bogus
</code></pre>
<h1 id="heading-the-queue-reader">The Queue Reader</h1>
<p>To kickoff, the <code>QueueReader</code> will be a generic <code>BackgroundService</code> defined as below, including all <em>usings</em>:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> Azure.Messaging.ServiceBus;
<span class="hljs-keyword">using</span> Microsoft.Extensions.Hosting;
<span class="hljs-keyword">using</span> Microsoft.Extensions.Logging;
<span class="hljs-keyword">using</span> <span class="hljs-keyword">static</span> System.Threading.CancellationTokenSource;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">ConcurrentFlows.AzureBusSeries.Part4.Reader</span>;

<span class="hljs-keyword">public</span> <span class="hljs-keyword">sealed</span> <span class="hljs-keyword">class</span> <span class="hljs-title">QueueReader</span>&lt;<span class="hljs-title">T</span>&gt;
    : <span class="hljs-title">BackgroundService</span>,
    <span class="hljs-title">IAsyncDisposable</span>
{
}
</code></pre>
<p>Next, we'll declare our dependencies and any necessary members:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">sealed</span> <span class="hljs-keyword">class</span> <span class="hljs-title">QueueReader</span>&lt;<span class="hljs-title">T</span>&gt;
    : <span class="hljs-title">BackgroundService</span>,
    <span class="hljs-title">IAsyncDisposable</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ILogger&lt;QueueReader&lt;T&gt;&gt; logger;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ServiceBusProcessor processor;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IMessageHandler&lt;T&gt; handler;

    <span class="hljs-keyword">private</span> CancellationTokenSource? stoppingCts;
}
</code></pre>
<p>We have a <code>logger</code> as a general practice, our key <code>ServiceBusProcessor</code> that will read from the queue, and a <code>MessageHandler</code> that will be passed any message received.</p>
<p>Next, our <code>ServiceBusProcessor</code> requires the definition of two event handlers: <code>ProcessMessageAsync</code> and <code>ProcessErrorAsync</code>. We'll keep these simple and compact. <em>Process Message</em> will delegate to the <code>MessageHandler</code> including cancelleation. <em>Process Error</em> will log the error details and move on. We don't need to directly Ack/Nack or Complete/Abandon/DLQ the message as we're using the <em>Auto Complete</em> feature of the processor by default.</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">private</span> Task <span class="hljs-title">ProcessMessageAsync</span>(<span class="hljs-params">ProcessMessageEventArgs args</span>)</span>
{
    <span class="hljs-keyword">var</span> body = args.Message.Body;
    <span class="hljs-keyword">var</span> obj = body.ToObjectFromJson&lt;T&gt;();
    <span class="hljs-keyword">var</span> cts = CreateLinkedTokenSource(stoppingCts!.Token, args.CancellationToken);
    <span class="hljs-keyword">return</span> handler.HandleAsync(obj, cts.Token);
}

<span class="hljs-function"><span class="hljs-keyword">private</span> Task <span class="hljs-title">ProcessErrorAsync</span>(<span class="hljs-params">ProcessErrorEventArgs args</span>)</span>
{
    logger.LogWarning(<span class="hljs-string">"Error Processing {@Error}"</span>,
        <span class="hljs-keyword">new</span>
        {
            args.Identifier,
            ErrorSource = <span class="hljs-string">$"<span class="hljs-subst">{args.ErrorSource}</span>"</span>,
            Exception = <span class="hljs-string">$"<span class="hljs-subst">{args.Exception}</span>"</span>
        });
    <span class="hljs-keyword">return</span> Task.CompletedTask;
}
</code></pre>
<p>Then, as a <code>BackgroundService</code> we need to implement the abstract <code>ExecuteAsync</code> method. The way we do this is key to interacting with our <em>Host</em>. A common pitfall is not recognizing that the Task returned from <code>ExecuteAsync</code> represents the lifetime of the <code>BackgroundService</code>.</p>
<p>The <code>ServiceBusProcessor</code> exposes two methods we're concerned with here: <code>StartProcessingAsync</code> and <code>StopProcessingAsync</code>. Each of these methods return a Task representing the operation itself, i.e. <em>Starting</em> or <em>Stopping</em>, but neither represents the ongoing processing. If we were to simply await <code>StartProcessingAsync</code> and leave it at that, our <em>Host</em> would consider the service <em>complete</em>, i.e. it's no longer running.</p>
<p>What we want is to <em>Start Processing</em>, and then, hold until the service is commanded to shut down, then we'll <em>Stop Processing.</em> To do this we'll create a helper extension method:</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> Task <span class="hljs-title">CompleteOnCancelAsync</span>(<span class="hljs-params">
    <span class="hljs-keyword">this</span> CancellationToken token</span>)</span>
{
    <span class="hljs-keyword">var</span> tcs = <span class="hljs-keyword">new</span> TaskCompletionSource();
    token.Register(t =&gt;
    {
        <span class="hljs-keyword">if</span> (t <span class="hljs-keyword">is</span> TaskCompletionSource tcs)
            tcs.TrySetResult();
    }, tcs);
    <span class="hljs-keyword">return</span> tcs.Task;
}
</code></pre>
<p>This converts the cancellation signal from a token into the completion of a Task.</p>
<p>With this in hand we can implement <code>ExecuteAsync</code></p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">ExecuteAsync</span>(<span class="hljs-params">CancellationToken stoppingToken</span>)</span>
{
    stoppingCts = CreateLinkedTokenSource(stoppingToken);
    <span class="hljs-keyword">await</span> processor.StartProcessingAsync(CancellationToken.None);

    <span class="hljs-keyword">await</span> stoppingToken.CompleteOnCancelAsync();

    stoppingCts.Cancel();
    <span class="hljs-keyword">await</span> processor.StopProcessingAsync(CancellationToken.None);
}
</code></pre>
<p>Within this method, we first create the linked token source that is later passed to our <code>MessageHandler</code>. Then we <em>Start,</em> await a shutdown signal, then cancel any outstanding processing, and finally <em>Stop</em> processing. The rest of the lifetime boiler plate is already within the <code>BackgroundService</code>.</p>
<p>Finally, we implement our constructor to inject dependencies and assign the event handling delegates. Also, we'll wrap everything up with async disposal.</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">QueueReader</span>(<span class="hljs-params">
    ILogger&lt;QueueReader&lt;T&gt;&gt; logger,
    ServiceBusProcessor processor,
    IMessageHandler&lt;T&gt; handler</span>)</span>
{
    <span class="hljs-keyword">this</span>.logger = logger.ThrowIfNull();
    <span class="hljs-keyword">this</span>.processor = processor.ThrowIfNull();
    <span class="hljs-keyword">this</span>.handler = handler.ThrowIfNull();

    processor.ProcessMessageAsync += ProcessMessageAsync;
    processor.ProcessErrorAsync += ProcessErrorAsync;
}

<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> ValueTask <span class="hljs-title">DisposeAsync</span>(<span class="hljs-params"></span>)</span>
{
    <span class="hljs-keyword">await</span> processor.DisposeAsync();
    stoppingCts?.Dispose();
    <span class="hljs-keyword">base</span>.Dispose();
}
</code></pre>
<p><em>All together now!</em></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">sealed</span> <span class="hljs-keyword">class</span> <span class="hljs-title">QueueReader</span>&lt;<span class="hljs-title">T</span>&gt;
    : <span class="hljs-title">BackgroundService</span>,
    <span class="hljs-title">IAsyncDisposable</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ILogger&lt;QueueReader&lt;T&gt;&gt; logger;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ServiceBusProcessor processor;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IMessageHandler&lt;T&gt; handler;

    <span class="hljs-keyword">private</span> CancellationTokenSource? stoppingCts;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">QueueReader</span>(<span class="hljs-params">
        ILogger&lt;QueueReader&lt;T&gt;&gt; logger,
        ServiceBusProcessor processor,
        IMessageHandler&lt;T&gt; handler</span>)</span>
    {
        <span class="hljs-keyword">this</span>.logger = logger.ThrowIfNull();
        <span class="hljs-keyword">this</span>.processor = processor.ThrowIfNull();
        <span class="hljs-keyword">this</span>.handler = handler.ThrowIfNull();

        processor.ProcessMessageAsync += ProcessMessageAsync;
        processor.ProcessErrorAsync += ProcessErrorAsync;
    }

    <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">ExecuteAsync</span>(<span class="hljs-params">CancellationToken stoppingToken</span>)</span>
    {
        stoppingCts = CreateLinkedTokenSource(stoppingToken);
        <span class="hljs-keyword">await</span> processor.StartProcessingAsync(CancellationToken.None);

        <span class="hljs-keyword">await</span> stoppingToken.CompleteOnCancelAsync();

        stoppingCts.Cancel();
        <span class="hljs-keyword">await</span> processor.StopProcessingAsync(CancellationToken.None);
    }

    <span class="hljs-function"><span class="hljs-keyword">private</span> Task <span class="hljs-title">ProcessMessageAsync</span>(<span class="hljs-params">ProcessMessageEventArgs args</span>)</span>
    {
        <span class="hljs-keyword">var</span> body = args.Message.Body;
        <span class="hljs-keyword">var</span> obj = body.ToObjectFromJson&lt;T&gt;();
        <span class="hljs-keyword">var</span> cts = CreateLinkedTokenSource(stoppingCts!.Token, args.CancellationToken);
        <span class="hljs-keyword">return</span> handler.HandleAsync(obj, cts.Token);
    }

    <span class="hljs-function"><span class="hljs-keyword">private</span> Task <span class="hljs-title">ProcessErrorAsync</span>(<span class="hljs-params">ProcessErrorEventArgs args</span>)</span>
    {
        logger.LogWarning(<span class="hljs-string">"Error Processing {@Error}"</span>,
            <span class="hljs-keyword">new</span>
            {
                args.Identifier,
                ErrorSource = <span class="hljs-string">$"<span class="hljs-subst">{args.ErrorSource}</span>"</span>,
                Exception = <span class="hljs-string">$"<span class="hljs-subst">{args.Exception}</span>"</span>
            });
        <span class="hljs-keyword">return</span> Task.CompletedTask;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> ValueTask <span class="hljs-title">DisposeAsync</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-keyword">await</span> processor.DisposeAsync();
        stoppingCts?.Dispose();
        <span class="hljs-keyword">base</span>.Dispose();
    }
}
</code></pre>
<hr />
<h1 id="heading-using-the-reader">Using the Reader</h1>
<p>To use the <code>QueueReader</code> we'll use our existing Service Bus Queue, create a message, a <code>QueueWriter</code>, a <code>MessageHandler</code>, and stand everything up in <em>Host.</em></p>
<p>First, the message we'll send looks like this notification, just an id and string content:</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">sealed</span> record <span class="hljs-title">Notification</span>(<span class="hljs-params">
    <span class="hljs-keyword">int</span> Id,
    <span class="hljs-keyword">string</span> Content</span>)</span>;
</code></pre>
<p>Then the <code>IMessageHandler</code> implementation receives the <code>Notification</code> and logs it:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">sealed</span> <span class="hljs-keyword">class</span> <span class="hljs-title">NotificationHandler</span>
    : <span class="hljs-title">IMessageHandler</span>&lt;<span class="hljs-title">Notification</span>&gt;
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ILogger&lt;NotificationHandler&gt; logger;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">NotificationHandler</span>(<span class="hljs-params">
        ILogger&lt;NotificationHandler&gt; logger</span>)</span>
        =&gt; <span class="hljs-keyword">this</span>.logger = logger.ThrowIfNull();

    <span class="hljs-function"><span class="hljs-keyword">public</span> Task <span class="hljs-title">HandleAsync</span>(<span class="hljs-params">Notification message, CancellationToken cancelToken</span>)</span>
    {
        logger.LogInformation(<span class="hljs-string">"Received Message:{NewLine}{Message}"</span>, 
            NewLine, message);
        <span class="hljs-keyword">return</span> Task.CompletedTask;
    }
}
</code></pre>
<p>The next major component is the <code>QueueWriter</code>, which is very similar to the <code>QueueSender</code> we created before. The main difference being this one sends a configured batch of messages. Also, we throw in a little <a target="_blank" href="https://github.com/bchavez/Bogus">Bogus</a> to get a fun, friendly, random name for the message.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">sealed</span> <span class="hljs-keyword">class</span> <span class="hljs-title">QueueWriter</span>
    : <span class="hljs-title">BackgroundService</span>,
    <span class="hljs-title">IAsyncDisposable</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ILogger&lt;QueueWriter&gt; logger;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ServiceBusSender sender;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> <span class="hljs-keyword">int</span> count;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> Faker faker = <span class="hljs-keyword">new</span>();

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">QueueWriter</span>(<span class="hljs-params">
        ILogger&lt;QueueWriter&gt; logger,
        ServiceBusSender sender,
        <span class="hljs-keyword">int</span> count = <span class="hljs-number">5</span></span>)</span>
    {
        <span class="hljs-keyword">this</span>.logger = logger.ThrowIfNull();
        <span class="hljs-keyword">this</span>.sender = sender.ThrowIfNull();
        <span class="hljs-keyword">this</span>.count = count;
    }

    <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">ExecuteAsync</span>(<span class="hljs-params">CancellationToken stoppingToken</span>)</span>
    {
        <span class="hljs-keyword">using</span> <span class="hljs-keyword">var</span> timeout = <span class="hljs-keyword">new</span> CancellationTokenSource(TimeSpan.FromSeconds(<span class="hljs-number">5</span>));
        <span class="hljs-keyword">using</span> <span class="hljs-keyword">var</span> cts = CreateLinkedTokenSource(stoppingToken);

        <span class="hljs-keyword">var</span> messages = Enumerable.Range(<span class="hljs-number">1</span>, count)
            .Select(id =&gt;
            {
                <span class="hljs-keyword">var</span> name = faker.Name.FirstName();
                <span class="hljs-keyword">var</span> notification = <span class="hljs-keyword">new</span> Notification(id, <span class="hljs-string">$"Hello from <span class="hljs-subst">{name}</span>"</span>);
                <span class="hljs-keyword">var</span> body = JsonSerializer.Serialize(notification);
                <span class="hljs-keyword">var</span> message = <span class="hljs-keyword">new</span> ServiceBusMessage(body);
                <span class="hljs-keyword">return</span> message;
            });

        <span class="hljs-keyword">await</span> sender.SendMessagesAsync(messages, stoppingToken);
        logger.LogInformation(<span class="hljs-string">"Finished"</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> ValueTask <span class="hljs-title">DisposeAsync</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-keyword">await</span> sender.DisposeAsync();
        <span class="hljs-keyword">base</span>.Dispose();        
    }
}
</code></pre>
<h1 id="heading-setting-up-the-host">Setting up the Host</h1>
<p>First, we'll setup credentials the same as we configured them earlier in <a target="_blank" href="https://concurrentflows.com/azure-service-bus-authentication-with-entra-identities-and-azure-credentials#heading-default-credentialing">Part 2 - Default Credentials</a></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title">CredentialBuilder</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> DefaultAzureCredential <span class="hljs-title">CreateDefaultCredential</span>(<span class="hljs-params">
        <span class="hljs-keyword">this</span> IConfiguration config</span>)</span>
    {
        <span class="hljs-keyword">var</span> tenantId = config[<span class="hljs-string">"TenantId"</span>];
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span>(<span class="hljs-keyword">new</span> DefaultAzureCredentialOptions()
        {
            TenantId = tenantId
        }.SetVisualStudioCredentialingOnly());
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> DefaultAzureCredentialOptions <span class="hljs-title">SetVisualStudioCredentialingOnly</span>(<span class="hljs-params">
        <span class="hljs-keyword">this</span> DefaultAzureCredentialOptions options</span>)</span>
    {
        options.ExcludeAzureCliCredential = <span class="hljs-literal">true</span>;
        options.ExcludeAzureDeveloperCliCredential = <span class="hljs-literal">true</span>;
        options.ExcludeAzurePowerShellCredential = <span class="hljs-literal">true</span>;
        options.ExcludeEnvironmentCredential = <span class="hljs-literal">true</span>;
        options.ExcludeInteractiveBrowserCredential = <span class="hljs-literal">true</span>;
        options.ExcludeVisualStudioCodeCredential = <span class="hljs-literal">true</span>;
        options.ExcludeWorkloadIdentityCredential = <span class="hljs-literal">true</span>;
        options.ExcludeManagedIdentityCredential = <span class="hljs-literal">true</span>;
        options.ExcludeSharedTokenCacheCredential = <span class="hljs-literal">true</span>;
        <span class="hljs-keyword">return</span> options;
    }
}
</code></pre>
<p>Then we have the registrations for our Service Bus components</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Registrations</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">const</span> <span class="hljs-keyword">string</span> Identifier = <span class="hljs-string">"AzureBusSeries"</span>;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> IServiceCollection <span class="hljs-title">AddAzureBusComponents</span>(<span class="hljs-params">
        <span class="hljs-keyword">this</span> IServiceCollection services</span>)</span>
        =&gt; services
        .AddAzureBusClient()
        .AddAzureBusSender()
        .AddAzureBusProcessor();

    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> IServiceCollection <span class="hljs-title">AddAzureBusClient</span>(<span class="hljs-params">
        <span class="hljs-keyword">this</span> IServiceCollection services</span>)</span>
        =&gt; services.AddSingleton(sp =&gt;
        {
            <span class="hljs-keyword">var</span> config = sp.GetRequiredService&lt;IConfiguration&gt;();

            <span class="hljs-keyword">var</span> credential = config.CreateDefaultCredential();
            <span class="hljs-keyword">var</span> hostName = config[<span class="hljs-string">"ServiceBusHost"</span>];

            <span class="hljs-keyword">var</span> options = <span class="hljs-keyword">new</span> ServiceBusClientOptions()
            {
                TransportType = ServiceBusTransportType.AmqpWebSockets,
                Identifier = <span class="hljs-string">$"<span class="hljs-subst">{Identifier}</span>-Client"</span>
            };

            <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> ServiceBusClient(hostName, credential, options);
        });

    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> IServiceCollection <span class="hljs-title">AddAzureBusSender</span>(<span class="hljs-params">
        <span class="hljs-keyword">this</span> IServiceCollection services</span>)</span>
        =&gt; services.AddSingleton(sp =&gt;
        {
            <span class="hljs-keyword">var</span> config = sp.GetRequiredService&lt;IConfiguration&gt;();
            <span class="hljs-keyword">var</span> client = sp.GetRequiredService&lt;ServiceBusClient&gt;();
            <span class="hljs-keyword">var</span> queue = config[<span class="hljs-string">"Queue"</span>];

            <span class="hljs-keyword">var</span> options = <span class="hljs-keyword">new</span> ServiceBusSenderOptions()
            {
                Identifier = <span class="hljs-string">$"<span class="hljs-subst">{Identifier}</span>-Writer"</span>
            };

            <span class="hljs-keyword">return</span> client.CreateSender(queue, options);
        });

    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> IServiceCollection <span class="hljs-title">AddAzureBusProcessor</span>(<span class="hljs-params">
        <span class="hljs-keyword">this</span> IServiceCollection services</span>)</span>
        =&gt; services.AddSingleton(sp =&gt;
        {
            <span class="hljs-keyword">var</span> config = sp.GetRequiredService&lt;IConfiguration&gt;();
            <span class="hljs-keyword">var</span> client = sp.GetRequiredService&lt;ServiceBusClient&gt;();
            <span class="hljs-keyword">var</span> queue = config[<span class="hljs-string">"Queue"</span>];

            <span class="hljs-keyword">var</span> options = <span class="hljs-keyword">new</span> ServiceBusProcessorOptions()
            {
                Identifier = <span class="hljs-string">$"<span class="hljs-subst">{Identifier}</span>-Reader"</span>
            };

            <span class="hljs-keyword">return</span> client.CreateProcessor(queue, options);
        });
}
</code></pre>
<p>And finally, we pull it all together in our <code>Program.cs</code></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> builder = Host.CreateApplicationBuilder();

builder.Configuration.AddUserSecrets&lt;Program&gt;();

builder.Logging.AddConsole();

builder.Services
    .AddHostedService&lt;QueueWriter&gt;()
    .AddHostedService&lt;QueueReader&lt;Notification&gt;&gt;()
    .AddSingleton&lt;IMessageHandler&lt;Notification&gt;, NotificationHandler&gt;()
    .AddAzureBusComponents();

<span class="hljs-keyword">var</span> app = builder.Build();

<span class="hljs-keyword">await</span> app.RunAsync();
</code></pre>
<h1 id="heading-execute"><em>Execute!!</em></h1>
<p>If you've got everything set up right and secrets configured, run the app and you'll see something like this logged to the console</p>
<pre><code class="lang-apache"><span class="hljs-attribute">info</span>: ConcurrentFlows.AzureBusSeries.Part<span class="hljs-number">4</span>.Writer.QueueWriter[<span class="hljs-number">0</span>]
      <span class="hljs-attribute">Finished</span>
<span class="hljs-attribute">info</span>: ConcurrentFlows.AzureBusSeries.Part<span class="hljs-number">4</span>.Handlers.NotificationHandler[<span class="hljs-number">0</span>]
      <span class="hljs-attribute">Received</span> Message:
      <span class="hljs-attribute">Notification</span> { Id = <span class="hljs-number">1</span>, Content = Hello from Caden }
<span class="hljs-attribute">info</span>: ConcurrentFlows.AzureBusSeries.Part<span class="hljs-number">4</span>.Handlers.NotificationHandler[<span class="hljs-number">0</span>]
      <span class="hljs-attribute">Received</span> Message:
      <span class="hljs-attribute">Notification</span> { Id = <span class="hljs-number">2</span>, Content = Hello from Rylan }
<span class="hljs-attribute">info</span>: ConcurrentFlows.AzureBusSeries.Part<span class="hljs-number">4</span>.Handlers.NotificationHandler[<span class="hljs-number">0</span>]
      <span class="hljs-attribute">Received</span> Message:
      <span class="hljs-attribute">Notification</span> { Id = <span class="hljs-number">3</span>, Content = Hello from Rubie }
<span class="hljs-attribute">info</span>: ConcurrentFlows.AzureBusSeries.Part<span class="hljs-number">4</span>.Handlers.NotificationHandler[<span class="hljs-number">0</span>]
      <span class="hljs-attribute">Received</span> Message:
      <span class="hljs-attribute">Notification</span> { Id = <span class="hljs-number">4</span>, Content = Hello from April }
<span class="hljs-attribute">info</span>: ConcurrentFlows.AzureBusSeries.Part<span class="hljs-number">4</span>.Handlers.NotificationHandler[<span class="hljs-number">0</span>]
      <span class="hljs-attribute">Received</span> Message:
      <span class="hljs-attribute">Notification</span> { Id = <span class="hljs-number">5</span>, Content = Hello from Katelin }
</code></pre>
<hr />
<h1 id="heading-wrap-up-amp-repo">Wrap Up &amp; Repo</h1>
<p>Here, we built a <code>BackgroundService</code> to host the <code>ServiceBusProcessor</code>. This kept the framework informed of our processing lifetime, delegated the message handling to a dependency and flowed all cancellation signals. Also, we built out the supporting components and gave our new <code>QueueReader</code> a test drive. Hopefully, this pattern is useful the next time you're creating a new event-driven dotnet app!</p>
<p><em>Happy Messaging!</em></p>
<p>Of course, all code is available on GitHub ⇒ <a target="_blank" href="https://github.com/ptsteward/ConcurrentFlows.HashNode/tree/master/ConcurrentFlows.AzureBusSeries">ConcurrentFlows.AzureBusSeries</a></p>
<p>If there's anything specific you'd like covered regarding Service Bus, please drop an ask in the comments!</p>
]]></content:encoded></item><item><title><![CDATA[Azure Service Bus: Integration Testing with xUnit and Admin Client]]></title><description><![CDATA[Service Bus Series - Part 3
The previous post, Part 2: Authentication and Sending to a Queue, covered authenticating to and writing to a Service Bus Queue. To do this we used the QueueSender background service. While this worked, it begs the question...]]></description><link>https://concurrentflows.com/azure-service-bus-integration-testing-with-xunit-and-admin-client</link><guid isPermaLink="true">https://concurrentflows.com/azure-service-bus-integration-testing-with-xunit-and-admin-client</guid><category><![CDATA[C#]]></category><category><![CDATA[Azure]]></category><category><![CDATA[Azure Service Bus]]></category><category><![CDATA[xunit]]></category><category><![CDATA[Integration Testing]]></category><category><![CDATA[event-driven-architecture]]></category><dc:creator><![CDATA[Joshua Steward]]></dc:creator><pubDate>Tue, 16 Apr 2024 21:45:43 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1713302924297/24793a7e-d070-4216-84e4-11d051ed1779.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-service-bus-series-part-3">Service Bus Series - Part 3</h1>
<p>The previous post, <a target="_blank" href="https://concurrentflows.com/azure-service-bus-authentication-with-entra-identities-and-azure-credentials">Part 2: Authentication and Sending to a Queue</a>, covered authenticating to and writing to a Service Bus Queue. To do this we used the <code>QueueSender</code> background service. While this worked, it begs the question; How do we test when integrating Azure Service Bus? That's exactly what we'll answer here!</p>
<h1 id="heading-queuesender-our-sut">QueueSender - Our SUT</h1>
<p>Our <em>System Under Test</em> for this exercise is the previously created <code>QueueSender</code>. This background service starts up, sends a single message, and completes. The entire service, <a target="_blank" href="https://concurrentflows.com/azure-service-bus-authentication-with-entra-identities-and-azure-credentials#heading-the-queuesender">from Part 2</a>, is given below:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">QueueSender</span>
    : <span class="hljs-title">BackgroundService</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ILogger&lt;QueueSender&gt; logger;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ServiceBusSender sender;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">QueueSender</span>(<span class="hljs-params">
        ILogger&lt;QueueSender&gt; logger,
        ServiceBusSender sender</span>)</span>

    {
        <span class="hljs-keyword">this</span>.logger = logger ?? <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentNullException(<span class="hljs-keyword">nameof</span>(logger));
        <span class="hljs-keyword">this</span>.sender = sender ?? <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentNullException(<span class="hljs-keyword">nameof</span>(sender));
    }

    <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">ExecuteAsync</span>(<span class="hljs-params">CancellationToken stoppingToken</span>)</span>
    {
        <span class="hljs-keyword">using</span> <span class="hljs-keyword">var</span> timeout = <span class="hljs-keyword">new</span> CancellationTokenSource(TimeSpan.FromSeconds(<span class="hljs-number">5</span>));
        <span class="hljs-keyword">using</span> <span class="hljs-keyword">var</span> cts = CancellationTokenSource.CreateLinkedTokenSource(stoppingToken, timeout.Token);
        <span class="hljs-keyword">try</span>
        {
            <span class="hljs-keyword">await</span> sender.SendMessageAsync(<span class="hljs-keyword">new</span>(<span class="hljs-string">"Hello World"</span>), cts.Token);

            logger.LogInformation(<span class="hljs-string">"Sent Message!!!"</span>);
        }
        <span class="hljs-keyword">catch</span> (OperationCanceledException ex) 
            <span class="hljs-keyword">when</span> (timeout.IsCancellationRequested)
        {
            logger.LogWarning(ex, <span class="hljs-string">"Operation timed out"</span>);
            <span class="hljs-keyword">throw</span>;
        }
        <span class="hljs-keyword">catch</span> (OperationCanceledException ex) 
            <span class="hljs-keyword">when</span> (stoppingToken.IsCancellationRequested)
        {
            logger.LogInformation(ex, <span class="hljs-string">"Shutdown early"</span>);
            <span class="hljs-keyword">throw</span>;
        }
        <span class="hljs-keyword">catch</span> (Exception ex)
        {
            logger.LogError(ex, <span class="hljs-string">"Unhandled exception"</span>);
            <span class="hljs-keyword">throw</span>;
        }
    }
}
</code></pre>
<h1 id="heading-what-well-test">What We'll Test</h1>
<p>This simple service presents a couple of unique challenges: it's a background service, and we're using Service Bus as a message broker. Testing a background service can be difficult since the only public methods are <code>StartAsync</code> &amp; <code>StopAsync</code>, this means we only have indirect access to the service. Testing with Service Bus is itself difficult since it cannot be ran locally and any test against it must treat it as the <em>shared</em> resource that it is.</p>
<p>With these considerations in mind, we'll focus our testing on integration and verify the following:</p>
<ol>
<li><p><strong>Does our system connect to our Service Bus?</strong></p>
</li>
<li><p><strong>Does the specified Queue exist?</strong></p>
</li>
<li><p><strong>Can we receive the message that we expect to be sent?</strong></p>
</li>
</ol>
<hr />
<h1 id="heading-xunit-project-setup">xUnit Project Setup</h1>
<p>To start we'll create a new <a target="_blank" href="https://xunit.net/">xUnit</a> test project via the following:</p>
<pre><code class="lang-csharp">dotnet <span class="hljs-keyword">new</span> xunit -o Part3
</code></pre>
<p>Next, add a reference to the project with our SUT, in my case <code>Part2.csproj</code></p>
<pre><code class="lang-csharp">dotnet <span class="hljs-keyword">add</span> reference Part2.csproj
</code></pre>
<p>Then, go ahead and delete <code>UnitTest1.cs</code></p>
<h1 id="heading-admin-client-creation">Admin Client Creation</h1>
<p>The key to integration testing an Azure Service Bus is the class <a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/azure.messaging.servicebus.administration.servicebusadministrationclient?view=azure-dotnet"><code>ServiceBusAdministrationClient</code></a> and the functionality it provides. From this client you can control, verify, and manipulate virtually anything about your Service Bus that you could via an IaC template or the Azure Portal itself.</p>
<p>Creating an Admin Client is as easy as creating a standard Service Bus Client. You only need the <code>fullyqualifiedNamespace</code>, a <code>tokenCredential</code>, and the default <code>ServiceBusAdministrationClientOptions</code> will work fine for our purpose.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">new</span> ServiceBusAdministrationClient(hostName, credentials, adminOptions);
</code></pre>
<p>Note though, the Identity and Credentials you use must have permissions to conduct the operations you require. <a target="_blank" href="https://concurrentflows.com/azure-service-bus-authentication-with-entra-identities-and-azure-credentials#heading-configuring-our-service-bus-namespace">The simple identity we set up previously will work for our tests</a>.</p>
<h1 id="heading-creating-the-test-fixture">Creating the Test Fixture</h1>
<p>For each of our 3 tests outlined above, we'll leverage the same underlying <em>Test Fixture</em>. This fixture will provide access to a fresh <code>IConfiguration</code>, our <code>ServiceBusAdminClient</code>, and provide a <code>ServiceBusReceiver</code>.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">sealed</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ServiceBusFixture</span>
    : <span class="hljs-title">IAsyncLifetime</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ServiceBusClient client;

    <span class="hljs-keyword">public</span> IConfiguration Config =&gt; BuildConfig();
    <span class="hljs-keyword">public</span> ServiceBusAdministrationClient AdminClient { <span class="hljs-keyword">get</span>; }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">ServiceBusFixture</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-keyword">var</span> credentials = Config.CreateDefaultCredential();
        <span class="hljs-keyword">var</span> hostName = Config[<span class="hljs-string">"ServiceBusHost"</span>];

        client = <span class="hljs-keyword">new</span> ServiceBusClient(hostName, credentials, <span class="hljs-keyword">new</span>()
        {
            TransportType = ServiceBusTransportType.AmqpWebSockets,
            Identifier = <span class="hljs-string">$"Test-Client"</span>
        });

        AdminClient = <span class="hljs-keyword">new</span> ServiceBusAdministrationClient(hostName, credentials, <span class="hljs-keyword">new</span>());
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> ServiceBusReceiver <span class="hljs-title">GetReceiver</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> queue</span>)</span>
        =&gt; client.CreateReceiver(queue, options: <span class="hljs-keyword">new</span>()
        {
            ReceiveMode = ServiceBusReceiveMode.ReceiveAndDelete,
            Identifier = <span class="hljs-string">$"Test-Receiver"</span>
        });

    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> IConfiguration <span class="hljs-title">BuildConfig</span>(<span class="hljs-params"></span>)</span>
        =&gt; <span class="hljs-keyword">new</span> ConfigurationBuilder()
        .AddUserSecrets&lt;ServiceBusFixture&gt;()
        .Build();

    <span class="hljs-function"><span class="hljs-keyword">public</span> Task <span class="hljs-title">InitializeAsync</span>(<span class="hljs-params"></span>)</span>
        =&gt; Task.CompletedTask;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">DisposeAsync</span>(<span class="hljs-params"></span>)</span>
        =&gt; <span class="hljs-keyword">await</span> (client?.DisposeAsync() ?? ValueTask.CompletedTask);
}
</code></pre>
<p>The Test Fixture also implements the <code>IAsyncLifetime</code> interface to properly dispose of the Service Bus Client after the tests complete.</p>
<h1 id="heading-testing-the-connection-and-queue">Testing the Connection and Queue</h1>
<p>Our first two tests can be combined;</p>
<ol>
<li><p><strong>Does our system connect to our Service Bus?</strong></p>
</li>
<li><p><strong>Does the specified Queue exist?</strong></p>
</li>
</ol>
<p>If we check for the existence of the specified Queue, we'll also ensure our connection to the Service Bus is working.</p>
<p>To test this, we'll create a new test file <code>ServiceBusConnectionTests.cs</code> and bring in our Test Fixture. From there we'll use the Admin Client to check for existence of the Queue within a given timeout since the operation is async and can fail.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">sealed</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ServiceBusConnectionTests</span>
    : <span class="hljs-title">IClassFixture</span>&lt;<span class="hljs-title">ServiceBusFixture</span>&gt;
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IConfiguration config;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ServiceBusAdministrationClient adminClient;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">ServiceBusConnectionTests</span>(<span class="hljs-params">ServiceBusFixture fixture</span>)</span>
    {
        ArgumentNullException.ThrowIfNull(fixture);

        config = fixture.Config
            ?? <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentNullException(<span class="hljs-keyword">nameof</span>(fixture.Config));
        adminClient = fixture.AdminClient
            ?? <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentNullException(<span class="hljs-keyword">nameof</span>(fixture.AdminClient));
    }

    [<span class="hljs-meta">Fact</span>]
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">Can_Connect_And_Queue_Exists</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-keyword">using</span> <span class="hljs-keyword">var</span> cts = <span class="hljs-keyword">new</span> CancellationTokenSource(TimeSpan.FromSeconds(<span class="hljs-number">3</span>));        
        <span class="hljs-keyword">var</span> queueName = config[<span class="hljs-string">"Queue"</span>];

        <span class="hljs-keyword">var</span> result = <span class="hljs-keyword">await</span> adminClient.QueueExistsAsync(queueName, cts.Token);

        Assert.True(result);
    }
}
</code></pre>
<h1 id="heading-testing-sending-and-receiving">Testing Sending and Receiving</h1>
<p>Our third test is a little more complicated:</p>
<ol start="3">
<li><strong>Can we receive the message that we expect to be sent?</strong></li>
</ol>
<p>We'll actually be creating an instance of our SUT, the <code>QueueSender</code>, and ensuring the message that we expect to be sent can then be received. Our test follows essentially four steps:</p>
<ol>
<li><p><strong>Create a temporary test queue and point our config to it</strong></p>
</li>
<li><p><strong>Create and start the background service</strong><code>QueueSender</code></p>
</li>
<li><p><strong>Receive any message from the test queue</strong></p>
</li>
<li><p><strong>Shutdown the</strong><code>QueueSender</code><strong>and cleanup the test queue</strong></p>
</li>
</ol>
<p>To begin, create a new test class <code>ServiceBusSenderTests.cs</code> and inject the Test Fixture:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">sealed</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ServiceBusSenderTests</span>
    : <span class="hljs-title">IClassFixture</span>&lt;<span class="hljs-title">ServiceBusFixture</span>&gt;,
    <span class="hljs-title">IAsyncLifetime</span>
{    
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ServiceBusAdministrationClient adminClient;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IConfiguration config;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ServiceBusReceiver receiver;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> <span class="hljs-keyword">string</span> testQueue;
    <span class="hljs-keyword">private</span> QueueProperties queueProps = <span class="hljs-keyword">default</span>!;    

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">ServiceBusSenderTests</span>(<span class="hljs-params">ServiceBusFixture fixture</span>)</span>
    {
        ArgumentNullException.ThrowIfNull(fixture);

        adminClient = fixture.AdminClient
            ?? <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentNullException(<span class="hljs-keyword">nameof</span>(fixture.AdminClient));
        config = fixture.Config
            ?? <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentNullException(<span class="hljs-keyword">nameof</span>(fixture.Config));

        testQueue = <span class="hljs-string">$"Test-<span class="hljs-subst">{Guid.NewGuid()}</span>"</span>;
        receiver = fixture.GetReceiver(testQueue);
    }
}
</code></pre>
<p>We generate a test queue name with the random UUID prefixed by 'Test' to identify it in case it isn't cleaned up. Then, we pull a new <code>ServiceBusReceiver</code> from our fixture pointed toward that test queue.</p>
<p>Then, we'll use the implementation of <code>IAsyncLifetime</code><strong>to get the existing</strong><code>QueueProperties</code><strong>during</strong><code>InitializeAsync</code><strong>, <em>this is an important step</em>.</strong> We could just create any random new queue, however, for our test to really ensure our <em>shared</em> queue is setup correctly, we need to duplicate it with its existing properties, only renamed.</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">InitializeAsync</span>(<span class="hljs-params"></span>)</span>
{
    <span class="hljs-keyword">using</span> <span class="hljs-keyword">var</span> cts = <span class="hljs-keyword">new</span> CancellationTokenSource(TimeSpan.FromSeconds(<span class="hljs-number">3</span>));
    <span class="hljs-keyword">var</span> queueName = config[<span class="hljs-string">"Queue"</span>];
    <span class="hljs-keyword">var</span> propsResponse = <span class="hljs-keyword">await</span> adminClient.GetQueueAsync(queueName, cts.Token);
    queueProps = propsResponse.Value;
}
</code></pre>
<p>Then in our <code>DisposeAsync</code> we'll use the <code>adminClient</code> to clean up the test queue if it has been created.</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">DisposeAsync</span>(<span class="hljs-params"></span>)</span>
{
    <span class="hljs-keyword">if</span> (adminClient <span class="hljs-keyword">is</span> <span class="hljs-literal">null</span>)
        <span class="hljs-keyword">return</span>;

    <span class="hljs-keyword">using</span> <span class="hljs-keyword">var</span> cts = <span class="hljs-keyword">new</span> CancellationTokenSource(TimeSpan.FromSeconds(<span class="hljs-number">3</span>));        
    <span class="hljs-keyword">var</span> queueExists = <span class="hljs-keyword">await</span> adminClient.QueueExistsAsync(queue, cts.Token);
    <span class="hljs-keyword">if</span> (queueExists)
        <span class="hljs-keyword">await</span> adminClient.DeleteQueueAsync(queue, cts.Token);
}
</code></pre>
<p>Next, we have a helper method to build the <code>QueueSender</code>. This sets up a Service Collection to register all dependencies and then create our <code>QueueSender</code> based on the <code>config</code> instance we will point to our test queue.</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">private</span> QueueSender <span class="hljs-title">BuildQueueSender</span>(<span class="hljs-params">IConfiguration config</span>)</span>
    =&gt; <span class="hljs-keyword">new</span> ServiceCollection()
    .AddSingleton(config)
    .AddSingleton&lt;QueueSender&gt;()
    .AddServiceBusForQueueSender()
    .AddLogging()
    .BuildServiceProvider()
    .GetRequiredService&lt;QueueSender&gt;();
</code></pre>
<p>Finally, in our test implementation we execute the following steps:</p>
<ol>
<li><p><strong>Update the</strong> <code>config</code> <strong>and create the test queue</strong></p>
</li>
<li><p><strong>Create and start the</strong> <code>QueueSender</code></p>
</li>
<li><p><strong>Receive and assert against any messages</strong></p>
</li>
<li><p><strong>Stop the</strong> <code>QueueSender</code></p>
</li>
</ol>
<p>We do this all within a 10 second timeout that ensures our test doesn't hang for too long and will move to clean up the test queue eventually.</p>
<pre><code class="lang-csharp">[<span class="hljs-meta">Fact</span>]
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">Can_Send_And_Receive_Message</span>(<span class="hljs-params"></span>)</span>
{
    <span class="hljs-keyword">using</span> <span class="hljs-keyword">var</span> cts = <span class="hljs-keyword">new</span> CancellationTokenSource(TimeSpan.FromSeconds(<span class="hljs-number">10</span>));
    config[<span class="hljs-string">"Queue"</span>] = testQueue;        
    <span class="hljs-keyword">await</span> adminClient.CreateQueueAsync(<span class="hljs-keyword">new</span> CreateQueueOptions(queueProps)
    {
        Name = testQueue
    }, cts.Token);

    <span class="hljs-keyword">var</span> sender = BuildQueueSender(config);
    <span class="hljs-keyword">await</span> sender.StartAsync(cts.Token);

    <span class="hljs-keyword">var</span> msg = <span class="hljs-keyword">await</span> receiver.ReceiveMessageAsync(TimeSpan.FromSeconds(<span class="hljs-number">2</span>), cts.Token);

    Assert.NotNull(msg);
    <span class="hljs-keyword">var</span> expecetd = <span class="hljs-string">"Hello World"</span>;
    Assert.Equal(expecetd, <span class="hljs-string">$"<span class="hljs-subst">{msg.Body}</span>"</span>);

    <span class="hljs-keyword">await</span> sender.StopAsync(cts.Token);
}
</code></pre>
<hr />
<h1 id="heading-wrap-up-amp-repo">Wrap Up &amp; Repo</h1>
<p>This was solid introduction to the <a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/azure.messaging.servicebus.administration.servicebusadministrationclient?view=azure-dotnet"><code>ServiceBusAdministrationClient</code></a>, many users of Azure Service Bus never get introduced to this very powerful component. Here, we've leveraged these capabilities to integration test our connection with Service Bus, the existence of a Queue, and ultimately to verify the functionality of a background service. With this approach, multiple engineers and CI/CD pipelines can execute these tests against our shared Service Bus resource without conflicting and causing flaky test results.</p>
<p>Of course, all code is available on GitHub ⇒ <a target="_blank" href="https://github.com/ptsteward/ConcurrentFlows.HashNode/tree/master/ConcurrentFlows.AzureBusSeries">ConcurrentFlows.AzureBusSeries</a></p>
<p>If there's anything specific you'd like covered regarding Service Bus, please drop an ask in the comments!</p>
]]></content:encoded></item><item><title><![CDATA[Azure Service Bus: Authentication with Entra, Identities, and Azure Credentials]]></title><description><![CDATA[Service Bus Series - Part 2
The previous post, Part 1: Creating an Azure Service Bus and Sending a Queue Message, covered setting up a basic Service Bus namespace, creating a simple queue and publishing a message via the Azure Portal. In this next pa...]]></description><link>https://concurrentflows.com/azure-service-bus-authentication-with-entra-identities-and-azure-credentials</link><guid isPermaLink="true">https://concurrentflows.com/azure-service-bus-authentication-with-entra-identities-and-azure-credentials</guid><category><![CDATA[azure-active-directory]]></category><category><![CDATA[Azure Service Bus]]></category><category><![CDATA[dotnet]]></category><category><![CDATA[event-driven-architecture]]></category><category><![CDATA[C#]]></category><dc:creator><![CDATA[Joshua Steward]]></dc:creator><pubDate>Wed, 03 Apr 2024 13:37:06 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1712150193580/e551fc22-282c-4f1c-ae46-405f56a1cf40.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-service-bus-series-part-2">Service Bus Series - Part 2</h1>
<p>The previous post, <a target="_blank" href="https://concurrentflows.com/creating-an-azure-service-bus-and-sending-a-queue-message">Part 1: Creating an Azure Service Bus and Sending a Queue Message</a>, covered setting up a basic Service Bus namespace, creating a simple queue and publishing a message via the Azure Portal. In this next part we'll begin interacting with the Azure Resources via code in C#, dotnet 8, setup auth with Azure Entra, and use an Azure Credential to access our namespace.</p>
<h1 id="heading-authenticating">Authenticating</h1>
<p>With Azure Service Bus there's two primary ways to authenticate a client app: <em>Credentials w/ RBAC</em>, and a <em>Keyed Connection String.</em> Standard best practice is to use a Credential via the <a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/azure.identity.defaultazurecredential?view=azure-dotnet"><code>DefaultAzureCredential</code></a> This allows us to ultimately leverage a <a target="_blank" href="https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-managed-service-identity"><em>Managed Identity</em></a> when our app is deployed to production, keeping our secrets out of configs, out of repos, and in the safest place they can be. That said, a simple connection string with a keyed access policy is an easy way to get started, but we won't cover that further here.</p>
<h1 id="heading-understanding-the-default-azure-credential">Understanding the Default Azure Credential</h1>
<p>The Default Azure Credential is a composite of many dedicated credentialing options. Among them you have Visual Studio integration, CLI tools, and many more:</p>
<blockquote>
<ul>
<li><p><a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/azure.identity.environmentcredential?view=azure-dotnet">EnvironmentCredential</a></p>
</li>
<li><p><a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/azure.identity.environmentcredential?view=azure-dotnet">WorkloadIdentityCr</a><a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/azure.identity.workloadidentitycredential?view=azure-dotnet">eden</a><a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/azure.identity.environmentcredential?view=azure-dotnet">tial</a></p>
</li>
<li><p><a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/azure.identity.environmentcredential?view=azure-dotnet">ManagedIdenti</a><a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/azure.identity.workloadidentitycredential?view=azure-dotnet">tyCredent</a><a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/azure.identity.environmentcredential?view=azure-dotnet">ial</a></p>
</li>
<li><p><a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/azure.identity.environmentcredential?view=azure-dotnet">SharedTokenCac</a><a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/azure.identity.managedidentitycredential?view=azure-dotnet">heCre</a><a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/azure.identity.workloadidentitycredential?view=azure-dotnet">den</a><a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/azure.identity.environmentcredential?view=azure-dotnet">tial</a></p>
</li>
<li><p><a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/azure.identity.environmentcredential?view=azure-dotnet">VisualStudioC</a><a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/azure.identity.workloadidentitycredential?view=azure-dotnet">r</a><a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/azure.identity.managedidentitycredential?view=azure-dotnet">eden</a><a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/azure.identity.workloadidentitycredential?view=azure-dotnet">tial</a></p>
</li>
<li><p><a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/azure.identity.environmentcredential?view=azure-dotnet">VisualStudioCodeC</a><a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/azure.identity.managedidentitycredential?view=azure-dotnet">reden</a><a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/azure.identity.environmentcredential?view=azure-dotnet">tial</a></p>
</li>
<li><p><a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/azure.identity.environmentcredential?view=azure-dotnet">AzureCliCrede</a><a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/azure.identity.workloadidentitycredential?view=azure-dotnet">ntia</a><a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/azure.identity.managedidentitycredential?view=azure-dotnet">l</a></p>
</li>
<li><p><a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/azure.identity.environmentcredential?view=azure-dotnet">AzurePowerShellCreden</a><a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/azure.identity.managedidentitycredential?view=azure-dotnet">t</a><a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/azure.identity.environmentcredential?view=azure-dotnet">ial</a></p>
</li>
<li><p><a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/azure.identity.environmentcredential?view=azure-dotnet">AzureDeveloper</a><a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/azure.identity.workloadidentitycredential?view=azure-dotnet">CliCrede</a><a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/azure.identity.environmentcredential?view=azure-dotnet">ntial</a></p>
</li>
<li><p><a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/azure.identity.environmentcredential?view=azure-dotnet">InteractiveB</a><a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/azure.identity.workloadidentitycredential?view=azure-dotnet">r</a><a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/azure.identity.managedidentitycredential?view=azure-dotnet">owse</a><a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/azure.identity.workloadidentitycredential?view=azure-dotnet">rCred</a><a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/azure.identity.environmentcredential?view=azure-dotnet">ential</a></p>
</li>
</ul>
<p>[1] <a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/azure.identity.defaultazurecredential?view=azure-dotnet">DefaultAzureCredential - Microsoft Learn</a></p>
</blockquote>
<p>Wow, right!? What this allows us to do is setup our local dev environment using one Credential, while our deployed app leverages the Managed Identity. The Managed Identity itself <strong><em>does not exist beyond Azure</em></strong>. That's right, any attempt to authenticate via a Managed Identity outside of Azure results in failure to reach the protected <code>169.254.169.254:80</code> token host.</p>
<h1 id="heading-configuring-our-service-bus-namespace">Configuring our Service Bus namespace</h1>
<p>Today, we'll focus on getting a simple local app authenticated to our Service Bus using the Visual Studio integration, but similar steps would be taken with the other user level credentialing options. We're not deploying today, so we'll table the full-fledged Managed Identity for another time, our focus is Service Bus, not Entra fun.</p>
<p>For reference, this is also well covered via Microsoft Learn ⇒ <a target="_blank" href="https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-dotnet-get-started-with-queues?tabs=passwordless#assign-roles-to-your-microsoft-entra-user">Quickstart - Assign roles to your Microsoft Entra user</a>, but we'll cover a little extra so ride with me here.</p>
<p>Our first step is to reach the Access Control section of Service Bus. This is done by clicking 'Access Control (IAM)' on the left ribbon. Then we'll 'Add role assignment' from the '+ Add' drop down.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712135788666/8280ff1c-0e3e-4bb3-959b-d51d4c23c8cb.png" alt class="image--center mx-auto" /></p>
<p>With the selection of Roles in view, we have three built-in Roles to choose from</p>
<blockquote>
<ul>
<li><p><a target="_blank" href="https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#azure-service-bus-data-owner">Azure Service Bus Data Owner</a>: Use this role to allow full access to Service Bus namespace and its entities (queues, topics, subscriptions, and filters)</p>
</li>
<li><p><a target="_blank" href="https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#azure-service-bus-data-sender">Azure Service Bus Data Sender</a>: Use this role to allow sending messages to Service Bus queues and topics.</p>
</li>
<li><p><a target="_blank" href="https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#azure-service-bus-data-receiver">Azure Service Bus Data Receiver</a>: Use this role to allow receiving messages from Service Bus queues and subscriptions.</p>
</li>
</ul>
<p>[2] <a target="_blank" href="https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-managed-service-identity#azure-built-in-roles-for-azure-service-bus">Azure built-in roles for Azure Service Bus | Microsoft Learn</a></p>
</blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712136167788/c64dfcfa-bd13-4d03-b14a-0414f8e4ad6f.png" alt class="image--center mx-auto" /></p>
<p>For our purposes, choose 'Azure Service Bus Data Owner' and select 'Next' at the bottom.</p>
<p>Now, we'll assign access to 'User, group, or service principal' by clicking '+ Select Members'. Next, if your identity is not already seen, use the search feature to find the correct Identity, select them and then we'll click 'Select' at the bottom of the dialog.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712136437347/acbdce88-036d-4cd2-8ba0-67287bfb81ab.png" alt class="image--center mx-auto" /></p>
<p>With the identity selected, click 'Review + assign' to move onto the final step and review your choices.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712137257045/57a1ffb5-678c-44f0-bc89-b3663e20c3c4.png" alt class="image--center mx-auto" /></p>
<p>During the review, ensure the scope of privilege is correct and you've chosen the correct role to assign the desired Identity. Finally, click 'Review + assign' once more:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712137361551/846fbc0f-4e2a-411e-bd9b-2a5931bf14d7.png" alt class="image--center mx-auto" /></p>
<p><strong><em>And that's it!</em></strong> The chosen Identity now has the Azure Service Bus Data Owner role, granting full access to the Service Bus namespace and its entities.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712137648491/a31928f0-6c07-45fe-bd1d-67c2ff7bf79c.png" alt class="image--center mx-auto" /></p>
<p>With that configured, we can now start building our first app, finally some code!</p>
<hr />
<h1 id="heading-app-building-time">App Building Time!</h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712137752653/4466c216-1032-42e3-8021-60db4e72d202.gif" alt class="image--center mx-auto" /></p>
<p>We're going to create a simple hosted application that authenticates with our <code>DefaultAzureCredential</code> and sends a single 'Hello World' message to our existing Service Bus Queue.</p>
<p><strong><em>Preparatory; Ensure you are signed into Visual Studio with the Identity you've granted Service Bus access to.</em></strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712141019845/b1d19b1b-1e49-4c92-ac36-360b20ad7dd7.png" alt class="image--center mx-auto" /></p>
<h1 id="heading-project-stand-up">Project Stand Up</h1>
<p>Moving right along, create an empty .Net 8 console app to work in, any way you like is fine:</p>
<pre><code class="lang-apache"><span class="hljs-attribute">dotnet</span> new console --framework net<span class="hljs-number">8</span>.<span class="hljs-number">0</span>
</code></pre>
<p>Next up we're going to need some packages:</p>
<pre><code class="lang-apache"><span class="hljs-attribute">dotnet</span> add package Azure.Identity
<span class="hljs-attribute">dotnet</span> add package Azure.Messaging.ServiceBus
<span class="hljs-attribute">dotnet</span> add package Microsoft.Extensions.Hosting
</code></pre>
<h1 id="heading-default-credentialing">Default Credentialing</h1>
<p>Diving right in now, create a new class to hold our extension methods:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Extensions</span>
{
}
</code></pre>
<p>First to go in here will be our Credential builder, the <code>DefaultAzureCredential</code> will of course attempt a variety of authenticating methods until one succeeds. Typically, you'd have a local Credential and an Azure deployed Credential, but here we are simply sticking with the <code>VisualStudioCredential</code> attached to your sign-in. So, we'll exclude all of the Credentials we don't need:</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> DefaultAzureCredentialOptions <span class="hljs-title">SetVisualStudioCredentialingOnly</span>(<span class="hljs-params"><span class="hljs-keyword">this</span> DefaultAzureCredentialOptions options</span>)</span>
{
    <span class="hljs-comment">//Not strictly necessary but less is more</span>
    options.ExcludeAzureCliCredential = <span class="hljs-literal">true</span>;
    options.ExcludeAzureDeveloperCliCredential = <span class="hljs-literal">true</span>;
    options.ExcludeAzurePowerShellCredential = <span class="hljs-literal">true</span>;
    options.ExcludeEnvironmentCredential = <span class="hljs-literal">true</span>;
    options.ExcludeInteractiveBrowserCredential = <span class="hljs-literal">true</span>;
    options.ExcludeVisualStudioCodeCredential = <span class="hljs-literal">true</span>;
    options.ExcludeWorkloadIdentityCredential = <span class="hljs-literal">true</span>;
    options.ExcludeManagedIdentityCredential = <span class="hljs-literal">true</span>;
    options.ExcludeSharedTokenCacheCredential = <span class="hljs-literal">true</span>;
    <span class="hljs-keyword">return</span> options;
}
</code></pre>
<p>Next to note about our credentialing is the appropriate Tenant Id. This is a bit buried in the docs, but left to its default Tenant Id the <code>VisualStudioCredential</code> may result in something like this:</p>
<blockquote>
<p>Azure.Identity.CredentialUnavailableException: Process "..\IDE\CommonExtensions\Microsoft\Asal\TokenService\Microsoft.Asal.TokenService.exe" has failed with unexpected error: TS003: Error, TS004: Unable to get access token. 'AADSTS50020: User account '{EUII Hidden}' from identity provider '<a target="_blank" href="http://live.com">live.com</a>'</p>
<p><strong><em>does not exist in tenant 'Microsoft Services'</em></strong></p>
</blockquote>
<p>Clearly the default Tenant here, emphasis mine, is incorrect. Following the underlying error code you'll find this ⇒ <a target="_blank" href="https://learn.microsoft.com/en-us/troubleshoot/azure/entra-id/app-integration/error-code-aadsts50020-user-account-identity-provider-does-not-exist">Error AADSTS50020 - ... | Microsoft Learn</a> which isn't all that helpful in this scenario. What needs to happen is our credentialing method needs the correct Tenant Id passed to it. You can find your Tenant Id with the helpful <a target="_blank" href="https://learn.microsoft.com/en-us/partner-center/find-ids-and-domain-names#find-the-microsoft-entra-tenant-id-and-primary-domain-name">Find tenant ID | Microsoft Learn</a>. Simply searching for Entra will get you to the 'Default Directory', or similar in your setup, where you'll find the Tenant Id you need:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712150595402/fb2c08bd-8c22-44db-999c-7957f97921f8.png" alt class="image--center mx-auto" /></p>
<p>You'll take that Tenant Id and either bring it in hardcoded or, as I've done, store it in local secrets.json via Secret Manager, [3] <a target="_blank" href="https://learn.microsoft.com/en-us/aspnet/core/security/app-secrets?view=aspnetcore-8.0&amp;tabs=windows#secret-manager">Safe storage of app secrets in development | Microsoft Learn</a></p>
<p>With that in config, we can finish setting up our Credential:</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> DefaultAzureCredential <span class="hljs-title">CreateDefaultCredential</span>(<span class="hljs-params"><span class="hljs-keyword">this</span> IConfiguration config</span>)</span>
{
    <span class="hljs-keyword">var</span> tenantId = config[<span class="hljs-string">"TenantId"</span>];
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span>(<span class="hljs-keyword">new</span> DefaultAzureCredentialOptions()
    {
        TenantId = tenantId
    }.SetVisualStudioCredentialingOnly());
}
</code></pre>
<h1 id="heading-service-bus-container-registration">Service Bus Container Registration</h1>
<p>Next, we'll set up our Service Bus components in the <code>IServiceCollection</code>, again in our <code>Extensions.cs</code></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">private</span> <span class="hljs-keyword">const</span> <span class="hljs-keyword">string</span> Identifier = <span class="hljs-string">"AzureBusSeries"</span>;

<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> IServiceCollection <span class="hljs-title">AddServiceBusForQueueSender</span>(<span class="hljs-params">
    <span class="hljs-keyword">this</span> IServiceCollection services</span>)</span>
    =&gt; services
    .AddSingleton(sp =&gt;
    {
        <span class="hljs-comment">//Resolve the formed Config</span>
        <span class="hljs-keyword">var</span> config = sp.GetRequiredService&lt;IConfiguration&gt;();
        <span class="hljs-comment">//Create our Credentials using the previously created methods</span>
        <span class="hljs-keyword">var</span> credential = config.CreateDefaultCredential();        
        <span class="hljs-comment">// {Your namespace}.servicebus.windows.net        </span>
        <span class="hljs-keyword">var</span> hostName = config[<span class="hljs-string">"ServiceBusHost"</span>];

        <span class="hljs-keyword">var</span> options = <span class="hljs-keyword">new</span> ServiceBusClientOptions()
        {
            <span class="hljs-comment">//Standard</span>
            TransportType = ServiceBusTransportType.AmqpWebSockets,
            <span class="hljs-comment">//Identify this client on the bus - best for logging</span>
            Identifier = <span class="hljs-string">$"<span class="hljs-subst">{Identifier}</span>-Client"</span>
        };

        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> ServiceBusClient(hostName, credential, options);
    })
    .AddSingleton(sp =&gt;
    {
        <span class="hljs-comment">//Resolve the formed Config</span>
        <span class="hljs-keyword">var</span> config = sp.GetRequiredService&lt;IConfiguration&gt;();
        <span class="hljs-comment">//Resolve the existing client</span>
        <span class="hljs-keyword">var</span> client = sp.GetRequiredService&lt;ServiceBusClient&gt;();
        <span class="hljs-comment">//Pull the Queue name</span>
        <span class="hljs-keyword">var</span> queue = config[<span class="hljs-string">"Queue"</span>];

        <span class="hljs-keyword">var</span> options = <span class="hljs-keyword">new</span> ServiceBusSenderOptions()
        {
            <span class="hljs-comment">//Identify this Sender to the bus - best for logging</span>
            Identifier = <span class="hljs-string">$"<span class="hljs-subst">{Identifier}</span>-Sender"</span>
        };

        <span class="hljs-keyword">return</span> client.CreateSender(queue, options);
    });
</code></pre>
<h1 id="heading-the-queuesender">The QueueSender</h1>
<p>Our hosted app contains a single process, it will be kicked off on app start up, send its message, and finally the app will wait for us to exit. The single process here takes the form of a simple <code>BackgroundService</code> that receives our configured <code>Logger&lt;T&gt;</code> and the registered <code>ServiceBusSender</code>. This keeps the lifetime of both the client and sender controlled via the <code>ServiceCollection/Provider</code>. Never insatiate a <em>Sender</em> per message, you will exhaust your connections and enjoy the failure.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">sealed</span> <span class="hljs-keyword">class</span> <span class="hljs-title">QueueSender</span>
    : <span class="hljs-title">BackgroundService</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ILogger&lt;QueueSender&gt; logger;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ServiceBusSender sender;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">QueueSender</span>(<span class="hljs-params">
        ILogger&lt;QueueSender&gt; logger,
        ServiceBusSender sender</span>)</span>

    {
        <span class="hljs-keyword">this</span>.logger = logger ?? <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentNullException(<span class="hljs-keyword">nameof</span>(logger));
        <span class="hljs-keyword">this</span>.sender = sender ?? <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentNullException(<span class="hljs-keyword">nameof</span>(sender));
    }

    <span class="hljs-comment">//Abstract class method impl, executes and ends    </span>
    <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">ExecuteAsync</span>(<span class="hljs-params">CancellationToken stoppingToken</span>)</span>
    {        
        <span class="hljs-keyword">using</span> <span class="hljs-keyword">var</span> timeout = <span class="hljs-keyword">new</span> CancellationTokenSource(TimeSpan.FromSeconds(<span class="hljs-number">5</span>));
        <span class="hljs-keyword">using</span> <span class="hljs-keyword">var</span> cts = CancellationTokenSource.CreateLinkedTokenSource(stoppingToken, timeout.Token);
        <span class="hljs-keyword">try</span>
        {
            <span class="hljs-keyword">await</span> sender.SendMessageAsync(<span class="hljs-keyword">new</span>(<span class="hljs-string">"Hello World"</span>), cts.Token);

            logger.LogInformation(<span class="hljs-string">"Sent Message!!!"</span>);
        }
        <span class="hljs-keyword">catch</span> (OperationCanceledException ex) 
            <span class="hljs-keyword">when</span> (timeout.IsCancellationRequested)
        {
            logger.LogWarning(ex, <span class="hljs-string">"Operation timed out"</span>);
            <span class="hljs-keyword">throw</span>;
        }
        <span class="hljs-keyword">catch</span> (OperationCanceledException ex) 
            <span class="hljs-keyword">when</span> (stoppingToken.IsCancellationRequested)
        {
            logger.LogInformation(ex, <span class="hljs-string">"Shutdown early"</span>);
            <span class="hljs-keyword">throw</span>;
        }
        <span class="hljs-keyword">catch</span> (Exception ex)
        {
            logger.LogError(ex, <span class="hljs-string">"Unhandled exception"</span>);
            <span class="hljs-keyword">throw</span>;
        }
    }
}
</code></pre>
<h1 id="heading-tying-it-together-programcs">Tying it Together - Program.cs</h1>
<p>Finally, the app standup in our Program.cs is very minimal. We create the App Builder, add our config, setup logging, register services, build the app, and run.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> builder = Host.CreateApplicationBuilder();

builder.Configuration.AddUserSecrets&lt;Program&gt;();

builder.Logging.AddConsole();

builder.Services
    .AddHostedService&lt;QueueSender&gt;()
    .AddServiceBusForQueueSender();

<span class="hljs-keyword">var</span> app = builder.Build();

<span class="hljs-keyword">await</span> app.RunAsync();
</code></pre>
<h1 id="heading-hello-world">Hello World!</h1>
<p>If you've been following along, the app should kick off, and logs should roll in like the following:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712149241034/6fee89b9-2850-47c0-af55-0b9cbd628159.png" alt class="image--center mx-auto" /></p>
<p>With that, check your Queue and our greeting message should have arrived:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712149281132/c56c157f-b150-450f-a22e-a74295ee92d0.png" alt class="image--center mx-auto" /></p>
<hr />
<h1 id="heading-wrap-up-amp-repo">Wrap Up &amp; Repo</h1>
<p>We're getting a bit deeper now. We've successfully authenticated our local app with our Credential. We've setup that process in our Service Bus Access Control and properly provisioned access to our Identity. Finally, we laid a foundation for deeper and more complex interaction with our Service Bus namespace. The first question that comes to my mind; <em>This is fine, but how would you test this?</em> If only Service Bus offered a Docker container 🙃</p>
<p>Of course, all code is available on GitHub ⇒ <a target="_blank" href="https://github.com/ptsteward/ConcurrentFlows.HashNode/tree/master/ConcurrentFlows.AzureBusSeries">ConcurrentFlows.AzureBusSeries</a></p>
<p>If there's anything specific you'd like covered regarding Service Bus, please drop an ask in the comments!</p>
]]></content:encoded></item><item><title><![CDATA[Creating an Azure Service Bus and Sending a Queue Message]]></title><description><![CDATA[Service Bus Series Kickoff!!!!
Welcome to my Azure Service Bus series! In this series we'll explore the widely used Azure Service Bus message broker, look at its features and capabilities, and how you can best leverage it in your projects.
My inspira...]]></description><link>https://concurrentflows.com/creating-an-azure-service-bus-and-sending-a-queue-message</link><guid isPermaLink="true">https://concurrentflows.com/creating-an-azure-service-bus-and-sending-a-queue-message</guid><category><![CDATA[Azure]]></category><category><![CDATA[Azure Service Bus]]></category><category><![CDATA[dotnet]]></category><category><![CDATA[event-driven-architecture]]></category><category><![CDATA[C#]]></category><dc:creator><![CDATA[Joshua Steward]]></dc:creator><pubDate>Wed, 03 Apr 2024 03:20:42 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1712110293592/c4eaa548-2b05-4e80-94e2-ece04febf4df.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-service-bus-series-kickoff">Service Bus Series Kickoff!!!!</h1>
<p>Welcome to my Azure Service Bus series! In this series we'll explore the widely used Azure Service Bus message broker, look at its features and capabilities, and how you can best leverage it in your projects.</p>
<p>My inspiration for this series came from the realization that while Service Bus is widely used in Azure/dotnet shops, there's not a lot of in-depth info and/or what's available is widely spread out and difficult to piece together. Many tutorials stop well short of the coolest features and capabilities that make Service Bus a great choice if you're working in Azure. Come on, why should Kafka get all the love?? 💘</p>
<h1 id="heading-create-the-service-bus">Create the Service Bus</h1>
<p>Within Azure everything is a <em>Resource</em>, and a 'Service Bus' takes the form of a <em>Service Bus Namespace</em>. This is essentially where you will send messages that ultimately get delivered to a <em>Queue, Topic/Subscription.</em></p>
<p>To create the Service Bus Namespace from the portal, first log into your account and/or start your free trial here ⇒ <a target="_blank" href="https://azure.microsoft.com/en-us/free">Azure Free Account</a></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712107116261/923454db-5d52-4eb2-b5cd-d43f254816f0.png" alt class="image--center mx-auto" /></p>
<p>Once you're into the portal, simply search for 'Service Bus' in the marketplace:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712107268932/723515bb-2136-436c-91d6-9c744d72a246.png" alt class="image--center mx-auto" /></p>
<p>Next review the details and click 'Create':</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712107342175/6b2f139c-b4ff-4ed4-a0b4-697a7052086a.png" alt class="image--center mx-auto" /></p>
<p>Next, you'll follow the creation wizard. Start by entering you're Azure Subscription and the new/existing Resource Group the Namespace will live in.</p>
<p>Then, enter the Namespace name to use. This will become the name of the Service Bus and part of your connection string.</p>
<p>Also, select your local region to deploy the Service Bus Namespace.</p>
<p>Finally, select a pricing tier from the available options detailed here ⇒ <a target="_blank" href="https://azure.microsoft.com/en-us/pricing/details/service-bus/">Pricing Tiers - Service Bus</a></p>
<p>I've chosen 'Basic' to get us started, but feel free to go wild! Keep in mind 'Basic' will only let us create Queues, but we can upgrade later.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712107779756/bd0fe906-e799-4624-b884-f0691c4e6154.png" alt class="image--center mx-auto" /></p>
<p>We'll skip across some nuance by clicking 'Review + Create'. This is where you'll see a summary of what you entered and what will be deployed. When you're satisfied with your selections, click 'Create':</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712108006516/7c445da0-1146-44ea-b356-3847a19cabd5.png" alt class="image--center mx-auto" /></p>
<p>Wait for the deployment to complete, once it's done, you can view the Resource Overview seeing the details of your shiny new Service Bus! <em>I've removed some of my details 😉</em></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712114321216/293f0130-608f-44c1-b49b-715836c0125e.png" alt class="image--center mx-auto" /></p>
<p><strong><em>And that's it, you now have a Service Bus Namespace!!!</em></strong></p>
<h1 id="heading-create-a-queue">Create a Queue</h1>
<p>In Service Bus you have Queues and Topics. Queues are First-In-First-Out, FIFO, and each message will be delivered to one single consumer. A Topic though, has a set of Subscriptions and each Subscription acts as a FIFO Queue. This lets Topics implement Fan-Out or Pub/Sub. We'll get into more options, settings and nuance later but that's the basics.</p>
<p>To make our Namespace a bit more useful we'll start with a simple Queue. Select either '+ Queue' at the top or from the left ribbon:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712114306603/0279a560-5ded-4b5b-914d-dec7071db5c9.png" alt class="image--center mx-auto" /></p>
<p>A creation dialog will appear where you can configure your new Queue. Enter a <em>Name,</em> select the maximum queue size, TTL, Lock Duration, etc. You'll see below I've set the following:</p>
<ul>
<li><p>Max size to the minimum 1 GB</p>
</li>
<li><p>Max delivery count of 3</p>
</li>
<li><p>TTL reduced to 10 minutes</p>
</li>
<li><p>Lock duration of a quick 1 minute</p>
</li>
<li><p>And you can leave the final two check boxes unchecked</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712108876383/96ac7335-679d-4f98-8867-b1a6ff9f8059.png" alt class="image--center mx-auto" /></p>
<p>Click 'Create', and <strong><em>Boom!</em></strong> you now have a simple Queue!</p>
<h1 id="heading-first-message-from-the-portal">First Message, <em>From the Portal</em></h1>
<p>For your first message, let's simply use the portal before we dive into code in the next post.</p>
<p>To send a message first open the details of your Queue by clicking on it from the Overview. From there, enter the 'Service Bus Explorer':</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712114345914/0235af82-a482-4519-b13a-019079fb9473.png" alt class="image--center mx-auto" /></p>
<p>Once in the Explorer, click on 'Send messages'. From here you can send different content types, bodies, and set various properties. For the first one, let's send the classic 'Hello World' greeting:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712109574651/770dbf6f-33d9-42fc-bee6-172f4b85c2aa.png" alt class="image--center mx-auto" /></p>
<p>Once you've clicked 'Send', set your <em>Mode</em> by clicking 'Peek Mode' and switch it to 'Receive Mode', then click on 'Receive messages'. Be sure to select 'ReceiveAndDelete' on the dialog that pops up.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712109820728/3cfe3666-c737-4378-b333-7dbeabf44071.png" alt class="image--center mx-auto" /></p>
<p>Finally click 'Receive' and you'll be greeted by your message in the kindest way!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712109928935/f5690a12-dbee-45d7-894d-e4f3d5353ecc.png" alt class="image--center mx-auto" /></p>
<p><em>Don't you love that 'Paint' styling!?</em></p>
<hr />
<h1 id="heading-wrap-up">Wrap Up</h1>
<p>Quick and simple kickoff post; we created a Service Bus Namespace, created a Queue, finally sent and received a message on that Queue. Next we'll dive a layer deeper and start interacting with the Service Bus via a dotnet app.</p>
<p>If there's anything specific you'd like covered regarding Service Bus, please drop an ask in the comments!</p>
]]></content:encoded></item><item><title><![CDATA[Understanding Architectural Coupling]]></title><description><![CDATA[Types of Coupling
Coupling comes in many variations and can sneak into a system if care is not taken. Within Software Engineering we can generally say that coupling is -

the degree of interdependence between software modules; a measure of how closel...]]></description><link>https://concurrentflows.com/understanding-architectural-coupling</link><guid isPermaLink="true">https://concurrentflows.com/understanding-architectural-coupling</guid><category><![CDATA[architecture]]></category><category><![CDATA[Software Engineering]]></category><category><![CDATA[software architecture]]></category><category><![CDATA[distributed system]]></category><category><![CDATA[event-driven-architecture]]></category><dc:creator><![CDATA[Joshua Steward]]></dc:creator><pubDate>Sat, 18 Feb 2023 23:27:23 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1676761812076/56f6eb94-d6b4-4e2b-a942-a4a0242f9557.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-types-of-coupling">Types of Coupling</h1>
<p>Coupling comes in many variations and can sneak into a system if care is not taken. Within Software Engineering we can generally say that coupling is -</p>
<blockquote>
<p>the degree of interdependence between software modules; a measure of how closely connected two routines or modules are [1]</p>
</blockquote>
<p>To break things down in more detail we have -</p>
<p><strong><em>Data Type Coupling</em></strong></p>
<ol>
<li><p><strong>Content Coupling</strong> - Directly accessing and changing the data in another module</p>
</li>
<li><p><strong>Common Coupling</strong> - Two modules sharing a global data structure</p>
</li>
<li><p><strong>Data Coupling</strong> - A module passing data into another module through parameters or global data</p>
</li>
</ol>
<p><strong><em>Functional Type Coupling</em></strong></p>
<ol>
<li><p><strong>Control Coupling</strong> - A module controlling the flow of execution in another module</p>
</li>
<li><p><strong>Stamp/Temporal Coupling</strong> - Depending on the order of execution of other modules</p>
</li>
<li><p><strong>Functional Coupling</strong> - A module's output becomes another module's input</p>
</li>
</ol>
<p><strong><em>Platform Type Coupling</em></strong></p>
<ol>
<li><p><strong>Message Coupling</strong> - Communicating through a shared message-passing interface</p>
</li>
<li><p><strong>Interop Coupling</strong> - Modules are dependent directly on a single platform's technology or protocols</p>
</li>
</ol>
<hr />
<p>But what does this look like as we take our level of abstraction higher?</p>
<h1 id="heading-coupling-boundary">Coupling Boundary</h1>
<p>As we look at <em>Distributed Software Systems</em> we need a higher level of abstraction to examine the coupling between elements. This abstraction is known as the <strong><em>Architectural Quantum</em></strong>. An <em>Architectural Quantum</em> is defined from one perspective as an <em>"independently deployable artifact, with high cohesion, high static coupling and synchronous dynamic coupling"</em> [2]</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676757198188/61b44d97-ce35-460c-b374-ed3217e11788.png" alt class="image--center mx-auto" /></p>
<p>The relationship to coupling is clear and we can define a <em>Quantum</em> as a bounded system exhibiting, <em>high static coupling</em> and <em>synchronous dynamic coupling.</em> These forms of coupling force the bounded system to be deployed as a unit that may eschew high cohesion.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676757206313/9dddd316-04d5-4fc3-9fbc-10ac188bcb22.png" alt class="image--center mx-auto" /></p>
<p>Coupling, therefore, can cross even well-defined domain boundaries of microservices. Boundary crossing is what causes friction between teams and complex release strategies. Recognizing the underlying <em>Quantum</em> will enable us to eliminate unnecessary dependencies.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676757218330/bf0f58b1-7e2f-43a4-a63c-11e92d159de6.png" alt class="image--center mx-auto" /></p>
<h1 id="heading-the-razor-knowledge-discipline">The Razor - <em>Knowledge Discipline</em></h1>
<p>Architecting a complex software system, specifically applying <em>Continuous Architecture</em>, is all about managing volatility and maximizing the <em>Quality Attributes</em> of the system. Minimizing and analyzing coupling comes down to <strong>Knowledge Discipline*</strong>.*</p>
<blockquote>
<p><strong>Knowledge Discipline</strong> - Knowledge, being both data &amp; behavior, creates <em>Architectural Quantum</em> boundaries defined by singular ownership.</p>
</blockquote>
<p>Singular ownership of <em>Knowledge</em> means that only one <em>Quantum</em> can be the source of truth for a domain's behavior or data. Let's look at a tightly coupled eCommerce example.</p>
<h1 id="heading-knowledge-discipline-in-action">Knowledge Discipline - <em>In Action</em></h1>
<p>We'll look at the order placement system of, my favorite, Widgets Inc. Below it's clear the <em>Order Service</em> should not be orchestrating the downstream processes.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676759402159/51341b75-ea97-4137-8b4c-14e668390b26.png" alt class="image--center mx-auto" /></p>
<p>The <em>Order Service</em> has knowledge of the <em>Inventory Domain/Service</em>, also, it's aware of the <em>Notification Service</em>. Even worse, the <em>Inventory Service</em> is "validating" the Order for the <em>Order Service</em> based on its known inventory.</p>
<p>Due to the extraordinarily tight coupling among all three services, this system becomes a <em>Distributed Monolith.</em> Regardless of service breakdown, the tight coupling forms a single <em>Quantum</em> that must be deployed as a unit. Changes in one system ripple through others. If the individual services cannot be independently deployed, they're not "microservices" anymore. <strong><em>The monolith is simply further apart.</em></strong></p>
<p><strong>What a mess huh?</strong> Let's apply some <em>Discipline</em> between domains 🤓</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676759419417/a8d2029e-d48f-402a-aa72-60ed25f80023.png" alt class="image--center mx-auto" /></p>
<p>Here, both the <em>Order &amp; Inventory Services</em> listen for an Order Placed event. Independant of one another they execute their <em>Domain Responsibility</em>. The <em>Order Service</em> records the Order and the <em>Inventory Service</em> updates the Inventory. Neither knows anything about the other. The <em>Notification Service</em> recognizes the two resultant downstream events: Order Recorded &amp; Inventory Updated. Independently of any source of these events, the <em>Notification Service</em> executes its responsibility.</p>
<p>We have, however, traded the <strong><em>Data &amp; Control Coupling</em></strong> for <strong><em>Platform Coupling</em></strong> in the form of a <em>Message Broker</em>. This is a tradeoff we can live with and the reason why comes down to <strong>volatility.</strong></p>
<p>The <em>Message Broker</em> we've introduced offers a distinct and high 9s SLA. Also, as infrastructure, it's subject to very little change. New and evolving Business Requirements have none to little effect on the <em>Broker.</em> This provides us the tradeoff of depending on a <em>Message Broker</em> and in return, our domains become independent from one another.</p>
<h1 id="heading-wrapping-up">Wrapping Up</h1>
<p>Applying <strong><em>Knowledge Discipline</em></strong> gives us a technique to determine if there's an undesired coupling between modules. By identifying <em>knowledge</em> that has multiple owners we can identify hot spots of coupling. Slicing our system in terms of <em>knowledge ownership</em> keeps bounded data &amp; behavior independently deployable and executable.</p>
<hr />
<p>[1] Wikipedia contributors. (2022, May 6). <em>Coupling (computer programming)</em>. Wikipedia. <a target="_blank" href="https://en.wikipedia.org/wiki/Coupling_(computer_programming)">https://en.wikipedia.org/wiki/Coupling_(computer_programming)</a></p>
<p>[2] N. Ford, M. Richards, P. Sadalage, Z. Dehghani, <em>Software Architecture: The Hard Parts</em>. Sebastopol, CA: O'Reilly, 2022</p>
]]></content:encoded></item><item><title><![CDATA[Kafka Producer - C# Sync vs Async]]></title><description><![CDATA[Rules of Thumb
We're taught early and often that any I/O Bound operations should be done Asynchronously. A general rule of thumb is that anything that takes more than 50ms should be done async. While this is quite true in most cases, sometimes, just ...]]></description><link>https://concurrentflows.com/kafka-producer-sync-vs-async</link><guid isPermaLink="true">https://concurrentflows.com/kafka-producer-sync-vs-async</guid><category><![CDATA[C#]]></category><category><![CDATA[Apache Kafka]]></category><category><![CDATA[Confluent Kafka]]></category><category><![CDATA[event-driven-architecture]]></category><category><![CDATA[event streaming]]></category><dc:creator><![CDATA[Joshua Steward]]></dc:creator><pubDate>Wed, 25 Jan 2023 17:41:14 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1674666981811/2aba0d0e-b17d-45ed-ade0-53989904edc3.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-rules-of-thumb">Rules of Thumb</h1>
<p>We're taught early and often that any I/O Bound operations should be done <em>Asynchronously.</em> A general rule of thumb is that anything that takes more than 50ms should be done async. While this is quite true in most cases, sometimes, just seeing an option to run a method async, we default to that implementation without much forethought.</p>
<h1 id="heading-confluent-kafka-producer">Confluent Kafka Producer</h1>
<p><a target="_blank" href="https://www.confluent.io/">Confluent</a> offers a very nice <a target="_blank" href="https://kafka.apache.org/">Apache Kafka</a> integration NuGet package <a target="_blank" href="https://www.nuget.org/packages/Confluent.Kafka/">Confluent.Kafka</a>. Within this package you'll find nearly all the bits and pieces you'll need to connect with, consume and produce via Kafka. In particular, we'll look at the behavior of the default implementation of <code>IProducer&lt;TKey, TValue&gt;</code></p>
<p>To first set the stage we'll pull in some <a target="_blank" href="https://buf.build/">Protobuf</a> tooling via <a target="_blank" href="https://www.nuget.org/packages/Google.Protobuf/">Google.Protobuf</a> and <a target="_blank" href="https://www.nuget.org/packages/Grpc.Tools/">Grpc.Tools</a> NuGet packages. With those, we'll create a message as an instance of <code>Message&lt;TKey, TValue&gt;</code> with the following schema.</p>
<pre><code class="lang-apache"><span class="hljs-attribute">syntax</span> = <span class="hljs-string">"proto3"</span>;

<span class="hljs-attribute">package</span> ConcurrentFlows.KafkaProducer;

<span class="hljs-attribute">message</span> WidgetEvent {
    <span class="hljs-attribute">string</span> Greeting = <span class="hljs-number">1</span>;
}
</code></pre>
<h1 id="heading-benchmark-environment">Benchmark - Environment</h1>
<p>We'll need a local Kafka cluster to run our benchmarks against and we can <a target="_blank" href="https://github.com/ptsteward/ConcurrentFlows.HashNode/blob/master/ConcurrentFlows.KafkaProducer1/docker-compose.yml">docker-compose.yml</a> one up relatively easily via <code>docker-compose up -d</code>.</p>
<p>In addition to our cluster, we'll initialize two topics via <a target="_blank" href="https://github.com/ptsteward/ConcurrentFlows.HashNode/blob/master/ConcurrentFlows.KafkaProducer1/topic-init.sh">topic-init.sh</a>. One for a Sync Producer and one for an Async Producer.</p>
<p>Within our cluster, we've also stood up a <em>Schema Registry</em> and we'll use the associated Confluent NuGet package <a target="_blank" href="https://www.nuget.org/packages/Confluent.SchemaRegistry.Serdes.Protobuf">Confluent.SchemaRegistry.Serdes.Protobuf</a> This package brings in the necessary bits and pieces to talk to the <em>Schema Registry</em> and serialize/deserialize, (Ser/Des), our <em>Protobuf</em> messages.</p>
<p>Finally, to easily create messages we'll leverage the <a target="_blank" href="https://www.nuget.org/packages/Bogus">Bogus</a> NuGet package and create an instance of its <em>Faker;</em> <code>Faker&lt;WidgetEvent&gt; = new();</code>.</p>
<h1 id="heading-benchmark-setup">Benchmark - Setup</h1>
<p>The complete benchmark setup can be found within <a target="_blank" href="https://github.com/ptsteward/ConcurrentFlows.HashNode/blob/master/ConcurrentFlows.KafkaProducer1/ConcurrentFlows.KafkaProducer1/ProducerBenchmarks.cs">ProduceBenchmarks.cs</a></p>
<p>To benchmark both Async and Sync <code>Produce...</code> methods we'll use <a target="_blank" href="https://www.nuget.org/packages/BenchmarkDotNet">BenchmarkDotNet</a> and define a <code>IProducer&lt;TKey, TValue&gt;</code> for both Sync &amp; Async. Each <em>Producer</em> will share the same config for both itself and its <em>Registry.</em></p>
<p>Note: The default Acks setting is Acks = ALL. This means our <em>Producers</em> will wait for acknowledgment from all three replicas</p>
<p>First, the config</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> producerConfig = <span class="hljs-keyword">new</span> ProducerConfig()
{
    BootstrapServers = <span class="hljs-string">"localhost:9092,localhost:9093,localhost:9094"</span>,
    QueueBufferingMaxMessages = <span class="hljs-number">500</span>_000
};

<span class="hljs-keyword">var</span> registryConfig = <span class="hljs-keyword">new</span> SchemaRegistryConfig()
{
    Url = <span class="hljs-string">"localhost:8081"</span>,
};
</code></pre>
<p>Next, the <em>Schema Registry</em></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> registryClient = <span class="hljs-keyword">new</span> CachedSchemaRegistryClient(registryConfig);
</code></pre>
<p>Then, our Sync <em>Producer</em></p>
<pre><code class="lang-csharp">syncProducer = <span class="hljs-keyword">new</span> ProducerBuilder&lt;<span class="hljs-keyword">string</span>, WidgetEvent&gt;(producerConfig)
    .SetValueSerializer(
        <span class="hljs-keyword">new</span> ProtobufSerializer&lt;WidgetEvent&gt;(registryClient)
        .AsSyncOverAsync())
    .SetErrorHandler((p, e) 
        =&gt; Console.WriteLine(
            errorMessage, e.Code, e.Reason))
    .Build();
</code></pre>
<p>Finally, our Async <em>Producer</em></p>
<pre><code class="lang-csharp">asyncProducer = <span class="hljs-keyword">new</span> ProducerBuilder&lt;<span class="hljs-keyword">string</span>, WidgetEvent&gt;(producerConfig)
    .SetValueSerializer(
        <span class="hljs-keyword">new</span> ProtobufSerializer&lt;WidgetEvent&gt;(registryClient))
    .SetErrorHandler((p, e) 
        =&gt; Console.WriteLine(
            errorMessage, e.Code, e.Reason))
    .Build();
</code></pre>
<h1 id="heading-benchmarks-methods">Benchmarks - Methods</h1>
<p>We'll measure the performance of two methods of interest</p>
<ol>
<li><p><code>Produce("topic", TMessage, deliveryHandler)</code></p>
</li>
<li><p><code>ProduceAsync("topic", TMessage)</code></p>
</li>
</ol>
<pre><code class="lang-csharp">[<span class="hljs-meta">Benchmark</span>]
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">KafkaProducerSync</span>(<span class="hljs-params"></span>)</span>
{
    <span class="hljs-keyword">var</span> msg = <span class="hljs-keyword">new</span> Message&lt;<span class="hljs-keyword">string</span>, WidgetEvent&gt;()
    {
        Key = <span class="hljs-string">$"<span class="hljs-subst">{Guid.NewGuid()}</span>"</span>,
        Value = faker.Generate()
    };
    syncProducer.Produce(sync_topic, msg,
        d =&gt;
        {
            <span class="hljs-keyword">if</span> (d.Error.IsError)
                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> InvalidOperationException(
                    <span class="hljs-string">$"<span class="hljs-subst">{d.Error.Code}</span>:<span class="hljs-subst">{d.Error.Reason}</span>"</span>);
        });
}

[<span class="hljs-meta">Benchmark</span>]
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">KafkaProducerAsync</span>(<span class="hljs-params"></span>)</span>
{
    <span class="hljs-keyword">var</span> msg = <span class="hljs-keyword">new</span> Message&lt;<span class="hljs-keyword">string</span>, WidgetEvent&gt;()
    {
        Key = <span class="hljs-string">$"<span class="hljs-subst">{Guid.NewGuid()}</span>"</span>,
        Value = faker.Generate()
    };
    <span class="hljs-keyword">await</span> asyncProducer.ProduceAsync(async_topic, msg);
}
</code></pre>
<h2 id="heading-benchmarks-results">Benchmarks - Results</h2>
<p>Running the benchmarks is as simple as kicking off our console project in <code>Release</code></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> BenchmarkDotNet.Running;
<span class="hljs-keyword">using</span> ConcurrentFlows.KafkaProducer1;

Console.WriteLine(<span class="hljs-string">"Starting Producer Benchmarks"</span>);
BenchmarkRunner.Run&lt;ProducerBenchmarks&gt;();
</code></pre>
<p>On the same platform, with the same previously stood-up cluster</p>
<p><strong>Cluster -</strong></p>
<ul>
<li><p><strong>Network concurrentflows</strong> <em>- Created</em></p>
</li>
<li><p><strong>Container zookeeper</strong> <em>- Started</em></p>
</li>
<li><p><strong>Container broker3</strong> <em>- Started</em></p>
</li>
<li><p><strong>Container broker1</strong> <em>- Started</em></p>
</li>
<li><p><strong>Container broker2</strong> <em>- Started</em></p>
</li>
<li><p><strong>Container schema-registry</strong> <em>- Started</em></p>
</li>
<li><p><strong>Container rest-proxy</strong> <em>- Started</em></p>
</li>
<li><p><strong>Container topic-init</strong> <em>- Started</em></p>
</li>
</ul>
<p><strong>Platform -</strong></p>
<blockquote>
<p>BenchmarkDotNet=v0.13.4, OS=Windows 11 (10.0.22621.1105)<br />12th Gen Intel Core i9-12900HK, 1 CPU, 20 logical and 14 physical cores<br />.NET SDK=7.0.100<br />[Host] : .NET 7.0.0 (7.0.22.51805), X64 RyuJIT AVX2<br />DefaultJob : .NET 7.0.0 (7.0.22.51805), X64 RyuJIT AVX2</p>
</blockquote>
<p>We can see a significant difference between <code>Produce()</code> and <code>ProduceAsync()</code></p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Method</td><td>Mean</td><td>Error</td><td>StdDev</td><td>Gen0</td><td>Gen1</td><td>Allocated</td></tr>
</thead>
<tbody>
<tr>
<td>KafkaProducerSync</td><td>2.381 µs</td><td>0.0468 µs</td><td>0.0415 µs</td><td>0.5112</td><td>0.0076</td><td>6.24 KB</td></tr>
<tr>
<td>KafkaProducerAsync</td><td>15,291.646 µs</td><td>87.8239 µs</td><td>68.5671 µs</td><td>-</td><td>-</td><td>6.74 KB</td></tr>
</tbody>
</table>
</div><p><strong><em>Key Takeaway -</em></strong></p>
<blockquote>
<p><code>Produce()</code> <strong>is ~6,000 times faster than</strong> <code>ProduceAsync()</code> <strong><em>!!!</em></strong></p>
</blockquote>
<h1 id="heading-why-such-a-difference">Why such a difference???</h1>
<p>To begin with, note we had set <code>QueueBufferingMaxMessages</code> to 500,000. We did this because messages will stack up in the underlying <em>Producer</em> buffer as they work their way out to all replicas. Essentially, <code>Produce()</code> is <em>"Producing" faster than we're</em> <em>"Delivering".</em></p>
<p>The big highlight is that -</p>
<blockquote>
<p><strong>Both</strong> <code>Produce()</code> <strong>and</strong> <code>ProduceAsync()</code> <strong>are Asynchronous 🤓</strong></p>
</blockquote>
<ul>
<li><p><strong><em>ProduceAsync</em></strong> wraps the entire operation of <em>"Producing"</em> a message into a dotnet friendly <code>Task&lt;DeliveryResult&lt;TKey, TValue&gt;&gt;</code></p>
</li>
<li><p><strong><em>Produce</em></strong> leverages a callback style future defined by the third optional parameter <code>deliveryHandler</code></p>
</li>
</ul>
<p>This async style difference lets us decouple <em>"Producing"</em> from <em>"Delivering"</em> by deferring the handling of our <code>DeliveryReport&lt;TKey, TValue&gt;</code> . This is as opposed to waiting for a <code>DeliveryResult&lt;TKey, TValue&gt;&gt;</code> to be fully formed.</p>
<h1 id="heading-wrap-up">Wrap Up</h1>
<p>Now don't go change all your code to <code>Produce()</code> , it's still an unnecessary blocking call, albeit with minimal impact, even when your cluster is not <code>localhost</code> . What's important is to understand how these methods leverage asynchronicity in different ways and the way this impacts: Acknowledgement, Error Management, etc.</p>
<p>Ideally, I'd propose an entire separation of concerns of hot path message production and <em>Producing/Delivering</em> the message to the wire. That may be the subject of a future post. 🙃</p>
<p>Finally, find all relevant code here<br /><a target="_blank" href="https://github.com/ptsteward/ConcurrentFlows.HashNode/tree/master/ConcurrentFlows.KafkaProducer1">ConcurrentFlows.HashNode/ConcurrentFlows.KafkaProducer1</a></p>
]]></content:encoded></item><item><title><![CDATA[Event-Driven Caching]]></title><description><![CDATA[Purpose of Caching
As a Consumer of your shiny new service, I want my answers Now. Real-time has become the de facto standard. It's no longer good enough to take our time digging through millions of possibilities and return ~500ms later. Don't believ...]]></description><link>https://concurrentflows.com/event-driven-caching</link><guid isPermaLink="true">https://concurrentflows.com/event-driven-caching</guid><category><![CDATA[caching]]></category><category><![CDATA[Redis]]></category><category><![CDATA[event-driven-architecture]]></category><category><![CDATA[cache]]></category><category><![CDATA[Microservices]]></category><dc:creator><![CDATA[Joshua Steward]]></dc:creator><pubDate>Sat, 31 Dec 2022 17:00:42 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1672505778602/231ee592-fdb6-4426-bcb6-9b0389681e82.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-purpose-of-caching">Purpose of Caching</h1>
<p>As a <em>Consumer</em> of your shiny new service, I want my answers <strong><em>Now</em></strong>. Real-time has become the de facto standard. It's no longer good enough to take our time digging through millions of possibilities and return ~500ms later. Don't believe, either, that this only applies to user interactivity.</p>
<p>Caching allows an application to retrieve required data from an in-memory data store. While quite faster than digging within a more persistent store, the in-memory call is not free.</p>
<h1 id="heading-cache-on-demand">Cache On-Demand</h1>
<p>Typically, caches are remote with respect to the application itself. Even if local memory stores the cache, each call to the store increases the contention. The typical three-step process: first checks the cache and can return early, otherwise, the second step loads data out of the database, and third we cache the data for future use with a heuristic Time to Live (TTL). This <strong><em>On-Demand</em></strong> style is common among CRUD apps with a cache layer on top of a database-first mentality.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672421631987/3f7b0c67-fa4e-4951-af6c-613858c49820.png" alt class="image--center mx-auto" /></p>
<p>Cache On-Demand can encompass <a target="_blank" href="https://learn.microsoft.com/en-us/azure/architecture/patterns/cache-aside">Cache Aside, Read/Write Through, and Write Behind</a>, the patterns follow largely the same process. The owner of each step may vary or be done outside a hotter path. The key, though, is that each strategy requires <strong><em>Demand First and a Database Source of Truth (SoT).</em></strong></p>
<h1 id="heading-cache-ahead">Cache Ahead</h1>
<p><strong><em>Cache Ahead</em></strong> is all about <strong><em>Knowledge Management</em></strong>. <strong><em>Cache Ahead</em></strong> is more than simply <em>Write Through</em>. When we drive toward a realization of <em>real-time,</em> placing our slowest source of truth closest to our return is inefficient. In other words, even with a cache layer placed on top of a database, we've chosen the database as <strong><em>the true source</em></strong> of our data. We've relegated the cache to be little more than a band-aid on our architecture.</p>
<p>We need to take a better approach and address: <em>Writing</em>, <em>Lifetime</em>, and <em>Eviction</em> of cache data. Let's define this strategy by first dropping our CRUD preconceptions and viewing the problem through an Event-Driven lens.</p>
<h2 id="heading-widgets-inc">Widgets Inc.</h2>
<p>To stage an exploration of <strong><em>Cache Ahead</em></strong> we'll use the e-commerce unicorn Widgets Inc. The backend we're working with is composed of the <strong>Order Service,</strong> an <strong>Inventory Service</strong>, and <strong>Emal Service</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672497358161/34c9a64a-46a0-43ad-a66d-997d4e9d741e.png" alt class="image--center mx-auto" /></p>
<p>Specifically, let's explore the <strong>Order Service</strong>. Our service is such that it's both listening to Events and responding to HTTP Requests. I've placed the cache first in line with the database updated either via the App itself or in a <em>Write-Through</em> from our cache. We'll see <strong><em>Cache Ahead</em></strong> laid out as it would fulfill the following requirements of the <strong>Order Service</strong></p>
<ol>
<li><p>Validate an <code>OrderRequest</code> has <em>Products</em> in stock</p>
</li>
<li><p>Permit the ad-hoc querying of current <em>Orders</em></p>
</li>
<li><p>Maintain the Customers' <em>Order</em></p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672497968898/bbf0b4ad-0e0d-4b5e-86b3-79a1a69c2dbd.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-order-request-new-order">Order Request - New Order</h2>
<p>Keeping our <strong>Knowledge management</strong> perspective, a new <em>Order</em> must be validated and, if successful, persisted. This is the point in time when new knowledge enters our system.</p>
<p>We can assume that inventory has been maintained by our <strong>Inventory Service</strong>. We can confidently assume that, upon <em>Order</em> validation, we will hit the <strong>Inventory Service</strong> cache when checking stock levels. With a validated <em>Order,</em> we'll write to our cache.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672500273683/718dd300-4969-4aed-bb73-6464ab8d0f15.png" alt class="image--center mx-auto" /></p>
<p>This was relatively straightforward, much the same as a <em>Write-Through</em> wherein our database is backing up our cache. Note, the confident <strong>Inventory</strong> cache hit foreshadows how we'll <strong><em>Always</em></strong> have a <strong><em>Positive</em></strong> cache hit, i.e. if it's not in the cache it's not the database, no need to check, and the database is no longer an SoT.</p>
<h2 id="heading-ad-hoc-order-query">Ad-Hoc Order Query</h2>
<p>Permitting querying of any <em>Order</em> entails maintaining the <em>Order</em> during its active lifetime. Let's consider two external events that could occur affecting our <em>Order</em>: <code>CustomerNotified</code> and <code>InventoryUpdated</code> .</p>
<pre><code class="lang-apache"><span class="hljs-attribute">syntax</span> = <span class="hljs-string">"proto3"</span>;

<span class="hljs-attribute">message</span> CustomerNotified {
  <span class="hljs-attribute">string</span> MessageId = <span class="hljs-number">1</span>;
  <span class="hljs-attribute">string</span> CausationId = <span class="hljs-number">2</span>;
  <span class="hljs-attribute">string</span> CustomerId = <span class="hljs-number">3</span>;
  <span class="hljs-attribute">Kind</span> Kind = <span class="hljs-number">4</span>;

  <span class="hljs-attribute">enum</span> Kind {
    <span class="hljs-attribute">Confirmation</span> = <span class="hljs-number">1</span>;
    <span class="hljs-attribute">Cancellation</span> = <span class="hljs-number">2</span>;
    <span class="hljs-attribute">Backordered</span> = <span class="hljs-number">3</span>;
    <span class="hljs-attribute">Delivered</span> = <span class="hljs-number">4</span>;
  }
}

<span class="hljs-attribute">message</span> InventoryUpdated {
  <span class="hljs-attribute">string</span> MessageId = <span class="hljs-number">1</span>;
  <span class="hljs-attribute">string</span> CausationId = <span class="hljs-number">2</span>;
  <span class="hljs-attribute">string</span> ProductId = <span class="hljs-number">3</span>;
  <span class="hljs-attribute">int32</span> Count = <span class="hljs-number">4</span>;
}
</code></pre>
<p>Each message causes a <em>State Change</em> to our <em>Order</em>, we maintain our <em>Owned Domain</em> perspective and emit that an <em>Order</em> has been updated via an <code>OrderUpdated</code> event. The <strong>Order Service</strong> will not drive downstream events but simply state its own actions. In this way we maintain the current state of the <em>Order</em>, keeping the cache always the SoT.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672501847019/c76af6f9-9394-46a6-a114-5b271bf2ed0f.png" alt class="image--center mx-auto" /></p>
<p>We could have seen a variety of scenarios:</p>
<ol>
<li><p><code>Confirmation</code> ⇒<em>Order</em> is confirmed</p>
</li>
<li><p><code>Cancelleation</code> ⇒ <em>Order was</em> canceled</p>
</li>
<li><p><code>InventoryUpdated</code> ⇒ Business logic could drive a <code>Backordered</code></p>
</li>
</ol>
<p>Each of these cases would/could cause an <code>OrderUpdated</code> event. For instance, if a product becomes <code>Backordered</code> the Customer should be notified resulting in a <code>CustomerNotified | Backordered</code> event.</p>
<h2 id="heading-maintaining-the-order-eviction">Maintaining the Order - Eviction</h2>
<p>So far, we haven't discussed anything about a Time to Live (TTL) or Eviction Policy. Keeping in mind that our objective of <strong><em>Cache Ahead</em></strong> is such that our cache is the primary Source of Truth we want to avoid any form of database fallback. The hard persistent store in this case is better suited as an Event Sourcing store and/or disaster backup, i.e. not an operational store.</p>
<p>The first scary thought is usually that this implies an unbound cache lifetime and bloated cache size, with the cloud spend associated. However, consider the <strong>On-Demand</strong> cache strategy against <strong><em>Cache Ahead</em></strong> in our <strong>Order Service</strong> context. If there's no or little <em>demand</em> for current <em>Orders</em> they're evicted from the cache but in the same breath ask; Does that make sense in the use case? In other words; Why are <strong>active</strong> <em>Orders</em> not interesting enough to remain cached, and if so can we be comfortable with little more than a best guess heuristic TTL?</p>
<h3 id="heading-business-eviction">Business Eviction</h3>
<p><strong><em>Cache Ahead</em></strong> is distinctly intended for an Event-Driven Architecture (EDA). Within our EDA and <strong>Order Service</strong> context; an <em>Order</em> has a real-world business defined <em>Operational</em> lifetime<em>.</em> That's what determines just how <em>interesting</em> our <em>Order</em> is and determines its lifetime within the cache.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672503922199/ada3b8c6-4b90-4d34-b692-82de2f5ffcb8.png" alt class="image--center mx-auto" /></p>
<p>Our particular <strong>Order Service</strong> context can easily highlight <code>CustomerNotified | Delivered</code> as an End of Life (EoL) of the <em>Order</em>. Surely, we could have a <strong>Delivery Service</strong>, or live beyond via a 7-Day Return Policy, however;</p>
<blockquote>
<p>The key takeaway is that EoL is an event originating from the real life business context and our architecture reflects that reality.</p>
</blockquote>
<h1 id="heading-thats-a-wrap">That's a wrap</h1>
<p><strong><em>Cache Ahead</em></strong> is an Event-Driven caching strategy intended to meet the real-time needs of modern businesses. Oriented towards reflecting our real business operations and requirements. Databases don't go anywhere, but they begin to take a backseat operationally and serve analytics, backup, and recovery purposes.</p>
<p>What are your thoughts? What are the nuances I glossed over? Hit the comments and we'll chat!</p>
]]></content:encoded></item><item><title><![CDATA[Why I Orient Events to their Producer]]></title><description><![CDATA[Context
Event-Driven Architecture is an evolution of a more generic Microservices Architecture. With Microservice Architecture, responsibility is bound within defined domain boundaries and each service takes full ownership of its domain. Ideally, no ...]]></description><link>https://concurrentflows.com/why-i-orient-events-to-their-producer</link><guid isPermaLink="true">https://concurrentflows.com/why-i-orient-events-to-their-producer</guid><category><![CDATA[event-driven-architecture]]></category><category><![CDATA[messaging]]></category><category><![CDATA[Apache Kafka]]></category><category><![CDATA[apache pulsar]]></category><dc:creator><![CDATA[Joshua Steward]]></dc:creator><pubDate>Wed, 28 Dec 2022 18:04:04 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1672250142766/aa4a5966-1f6d-40a4-b6f7-acd6f908738a.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-context">Context</h1>
<p>Event-Driven Architecture is an evolution of a more generic Microservices Architecture. With Microservice Architecture, responsibility is bound within defined domain boundaries and each service takes full ownership of its domain. Ideally, no business operation would span across services and every task would fall neatly into a single microservices domain. Of course, the reality is more complicated and microservices must interact to accomplish any business operation. How they communicate becomes a paramount consideration and is exactly what Event-Driven Architecture addresses.</p>
<h1 id="heading-working-example">Working Example</h1>
<p>Consider the simple e-commerce example; Our company Widgets Inc. has a backend composed of an <strong>Order Service</strong>, <strong>Inventory Service</strong> and <strong>Email Service</strong>. When a Customer places an <em>Order</em> the <strong>Order Service</strong> must record the details of the <em>Order</em>, the <strong>Inventory Service</strong> needs to reflect the change in inventory and the <strong>Email Service</strong> must notify the <em>Customer</em> of their <em>Order</em> status. Fundamentally, the operations necessary from each service are well defined by the business; it's the degree of coupling among them we can control.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672239684473/c69146c1-8f9f-4744-8f46-1a5a7323eaad.png" alt class="image--center mx-auto" /></p>
<h1 id="heading-communicating">Communicating</h1>
<p>Great communication yields a resilient system and great communication is all about the degree of <em>Coupling</em>. When microservices work together they will need to communicate with one another. As microservices evolve independently from one another, communication between them requires deeper decoupling.</p>
<h2 id="heading-tight-and-dependant-synchronous">Tight and Dependant - Synchronous</h2>
<p>In a synchronous approach, services directly call http endpoints in a request/response model. This tightly couples the system together and can lead to cascading failure. Further, this approach can yield a distributed monolith, brittle and difficult to operate, all the benefits of microservices are lost.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672239694619/abffce5c-d046-43dd-88b8-22cae26fb717.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-ball-room-dancing-orchestration">Ball Room Dancing - Orchestration</h2>
<p>A slightly more asynchronous approach is to <a target="_blank" href="https://en.wikipedia.org/wiki/Orchestration_(computing)">Orchestrate</a> or <a target="_blank" href="https://en.wikipedia.org/wiki/Service_choreography">Choreograph</a> services within a workflow. In this approach, it's common to introduce an <strong>Orchestrator</strong>. An <strong>Orchestrator</strong> is responsible for coordinating the workflow and, if necessary, executing compensation upon failure. Here the services are only coupled to the <strong>Orchestrator</strong> while the <strong>Orchestrator</strong> is <strong><em>coupled</em></strong> to all participating services. This variation of tight coupling is due to treating this business operation as a <strong><em>Distributed Transaction</em></strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672239705227/4c6cf2cd-e345-439e-a67d-321bb6a034e5.png" alt class="image--center mx-auto" /></p>
<p>I'll place <em>Distributed Transactions, Orchestration vs Choreography</em> out of the scope of this post but each yield varying tradeoffs.</p>
<h1 id="heading-consider-the-events">Consider the Events</h1>
<p>In both our Synchronous and Asynchronous variations, our Events can be viewed as commands with implicit knowledge of the Workflow and the Consumer of the command.</p>
<h2 id="heading-bad-messages">Bad Messages</h2>
<p>For example, this might be our associated Message Schemas:</p>
<pre><code class="lang-apache"><span class="hljs-attribute">message</span> PlaceOrder {
  <span class="hljs-attribute">string</span> MessageId = <span class="hljs-number">1</span>;
  <span class="hljs-attribute">string</span> ProductId = <span class="hljs-number">2</span>;
  <span class="hljs-attribute">int32</span> Count = <span class="hljs-number">3</span>;
}

<span class="hljs-attribute">message</span> UpdateInventory {
  <span class="hljs-attribute">string</span> MessageId = <span class="hljs-number">1</span>;
  <span class="hljs-attribute">string</span> ProductId = <span class="hljs-number">2</span>;
  <span class="hljs-attribute">int32</span> Count = <span class="hljs-number">3</span>;
}

<span class="hljs-attribute">message</span> NotifyCustomer {
  <span class="hljs-attribute">string</span> MessageId = <span class="hljs-number">1</span>;
  <span class="hljs-attribute">string</span> CustomerId = <span class="hljs-number">2</span>;
  <span class="hljs-attribute">string</span> Status = <span class="hljs-number">3</span>;
}
</code></pre>
<p>Each <em>Message</em> is imperative and directs a <em>Consumer</em> to take action. Whether these messages are communicated Synchronously or Asynchronously is irrelevant. Within these messages lies the knowledge of <strong><em>What &amp; When</em></strong> to execute particular functions. This becomes a brittle distributed mess because each service must be oriented to execute within a predefined workflow there's no room for changes or discrete failure.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672239722115/2a7d4bc8-bdf3-4e95-9661-2afebfb99406.png" alt class="image--center mx-auto" /></p>
<p>Commands by their very nature mean the command source knows what must be done next. Whether it's an <strong>Orchestrator</strong> or the services are Choreographed, commanding one another spreads <strong><em>Knowledge</em></strong> where it shouldn't be. For example, within <code>NotifyCustomer</code> there's a string representing <code>Status</code> but exactly which domain understands <code>Status</code>?</p>
<h2 id="heading-better-approach">Better Approach</h2>
<p>What we must recognize is that <strong><em>Producers</em></strong> are discrete domains and we shouldn't muddy those separations. <strong><em>Events</em></strong> should reflect the perspective of the originating domain. This means that a single domain can only speak for itself. We won't let the <strong>Order Service</strong> command the <strong>Inventory Service</strong>. Neither will we need an <strong>Orchestrator</strong> to command our domains.</p>
<pre><code class="lang-apache"><span class="hljs-attribute">message</span> PlaceOrder {
  <span class="hljs-attribute">string</span> MessageId = <span class="hljs-number">1</span>;
  <span class="hljs-attribute">string</span> ProductId = <span class="hljs-number">2</span>;
  <span class="hljs-attribute">int32</span> Count = <span class="hljs-number">3</span>;
}

<span class="hljs-attribute">message</span> OrderPlaced {
  <span class="hljs-attribute">string</span> MessageId = <span class="hljs-number">1</span>;
  <span class="hljs-attribute">string</span> CausationId = <span class="hljs-number">2</span>;
  <span class="hljs-attribute">string</span> ProductId = <span class="hljs-number">3</span>;
  <span class="hljs-attribute">int32</span> Count = <span class="hljs-number">4</span>;
}

<span class="hljs-attribute">message</span> InventoryUpdated {
  <span class="hljs-attribute">string</span> MessageId = <span class="hljs-number">1</span>;
  <span class="hljs-attribute">string</span> CausationId = <span class="hljs-number">2</span>;
  <span class="hljs-attribute">string</span> ProductId = <span class="hljs-number">3</span>;
  <span class="hljs-attribute">int32</span> Count = <span class="hljs-number">4</span>;
}
</code></pre>
<p>Now we speak in the past tense after the <em>Order</em> is placed. Each domain simply states its domain knowledge. The <strong>Order Service</strong> can only say the <em>Order</em> is placed, it cannot tell anyone to update their inventory. It's the responsibility of the <strong>Inventory Service</strong> to know what to do when an <em>Order</em> is placed. Finally, our <strong>Email Service</strong> knows that the <em>Order</em> is placed and inventory is updated indicating a predefined <em>Customer</em> notification.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672241170825/bf450f30-727b-4d8b-932a-1e25915b316f.png" alt class="image--center mx-auto" /></p>
<p>More than simply a semantic argument, the underlying intention is to maintain domain integrity and service independence. The common contrary argument is that the state is more difficult to ascertain with this approach. Certainly a valid perspective, however, the state of any system is simply the aggregate of Events and can be known precisely via <code>Message</code> &amp; <code>Causation</code> Ids.</p>
<h1 id="heading-tldr">TL;DR</h1>
<blockquote>
<p>Events should reflect the perspective of the Producer and not implicitly dictate the Events' Consumption.</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[C# 11 List Patterns]]></title><description><![CDATA[C# and Pattern Matching
With each latest iteration of C#, we see more and more pattern matching. Frankly, I'm deeply excited to see this evolution. C# of course can still be considered an Object Oriented language but MS has taken the Multi-modal moni...]]></description><link>https://concurrentflows.com/c-11-list-patterns</link><guid isPermaLink="true">https://concurrentflows.com/c-11-list-patterns</guid><category><![CDATA[list patterns]]></category><category><![CDATA[c# 11]]></category><category><![CDATA[C#]]></category><category><![CDATA[dotnet7]]></category><category><![CDATA[pattern-matching]]></category><dc:creator><![CDATA[Joshua Steward]]></dc:creator><pubDate>Thu, 01 Dec 2022 16:54:29 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1669913465075/6w1SsrsTw.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-c-and-pattern-matching">C# and Pattern Matching</h1>
<p>With each latest iteration of C#, we see more and more pattern matching. Frankly, I'm deeply excited to see this evolution. C# of course can still be considered an Object Oriented language but MS has taken the <em>Multi-modal</em> moniker and then ran with it.</p>
<p>F# has been an incredible source of inspiration for the C# team, not to mention the Pythion influence when we left <code>Program</code> in the background. <em>So long old friend</em> 👋 We've seen a great deal of <em>Functionally</em> oriented features. From first-class tuples, immutable types, and of course pattern matching!</p>
<h1 id="heading-pattern-power">Pattern Power 💪</h1>
<h2 id="heading-what-is-a-pattern-again">What is a Pattern again?</h2>
<p>Simply put, a pattern is the shape of an input that you expect to see. You declare what to expect and allow our friend Roslyn to create the ultimate boolean expression to fulfill the pattern search.</p>
<h2 id="heading-list-patterns">List Patterns</h2>
<p>The latest addition to the crowd is <code>List Patterning</code> We can take any sequence and describe what we'd like to <code>switch</code> on from a mix of syntax cues.</p>
<p>Patterns are described by</p>
<ul>
<li>Square brackets <code>[]</code></li>
</ul>
<p>Within the brackets, we can match</p>
<ul>
<li><p>Any single element <code>_</code> with the <strong><em>Discard Pattern</em></strong></p>
</li>
<li><p>Many contiguous elements <code>..</code> with the <strong><em>Slice Pattern</em></strong></p>
</li>
</ul>
<p>We can even mix in existing patterns to further refine our Sequence Pattern</p>
<ul>
<li><p><strong><em>Relational Patterns</em></strong> <code>&lt;</code> , <code>&gt;=</code> , etc.</p>
</li>
<li><p><strong><em>Logical Patterns</em></strong> <code>and</code>, <code>or</code> , <code>not</code></p>
</li>
</ul>
<p><strong>And don't forget!</strong> Even with these complex <strong><em>List Patterns</em></strong> we still have a bit of a safety net to enforce fully closed pattern expressions as usual with <code>switch {}</code></p>
<hr />
<h2 id="heading-to-action-the-basics"><em>To Action - The basics</em></h2>
<p>We have a basic <strong><em>Discard</em></strong> match</p>
<pre><code class="lang-csharp">[<span class="hljs-meta">Fact</span>]
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Match_Discard_Pattern</span>(<span class="hljs-params"></span>)</span>
{
    <span class="hljs-keyword">var</span> seq = <span class="hljs-keyword">new</span>[] { <span class="hljs-number">1</span>, <span class="hljs-number">2</span> };
    <span class="hljs-keyword">var</span> result = seq <span class="hljs-keyword">switch</span>
    {
        [<span class="hljs-meta">_, 2</span>] =&gt; <span class="hljs-literal">true</span>,
        _ =&gt; <span class="hljs-literal">false</span>
    };
    result.Should().BeTrue();
}
</code></pre>
<p>Next, we'll <strong><em>Slice</em></strong> the sequence</p>
<pre><code class="lang-csharp">[<span class="hljs-meta">Fact</span>]
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Match_Slice_Pattern</span>(<span class="hljs-params"></span>)</span>
{
    <span class="hljs-keyword">var</span> seq = <span class="hljs-keyword">new</span>[] { <span class="hljs-number">1</span>, <span class="hljs-number">2</span> };
    <span class="hljs-keyword">var</span> result = seq <span class="hljs-keyword">switch</span>
    {
        [<span class="hljs-meta">..</span>] =&gt; <span class="hljs-literal">true</span>,
        _ =&gt; <span class="hljs-literal">false</span>
    };
    result.Should().BeTrue();
}
</code></pre>
<p>We can use <strong><em>Relational Patterns</em></strong></p>
<pre><code class="lang-csharp">[<span class="hljs-meta">Fact</span>]
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Match_Relational_Pattern</span>(<span class="hljs-params"></span>)</span>
{
    <span class="hljs-keyword">var</span> seq = <span class="hljs-keyword">new</span>[] { <span class="hljs-number">1</span>, <span class="hljs-number">2</span> };
    <span class="hljs-keyword">var</span> result = seq <span class="hljs-keyword">switch</span>
    {
        [<span class="hljs-meta">_, &gt; 1</span>] =&gt; <span class="hljs-literal">true</span>,
        _ =&gt; <span class="hljs-literal">false</span>
    };
    result.Should().BeTrue();
}
</code></pre>
<p>We can even mix in <strong><em>Logical Patterns</em></strong></p>
<pre><code class="lang-csharp">[<span class="hljs-meta">Fact</span>]
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Match_Relational_Logical_Pattern</span>(<span class="hljs-params"></span>)</span>
{
    <span class="hljs-keyword">var</span> seq = <span class="hljs-keyword">new</span>[] { <span class="hljs-number">1</span>, <span class="hljs-number">2</span> };
    <span class="hljs-keyword">var</span> result = seq <span class="hljs-keyword">switch</span>
    {
        [<span class="hljs-meta">_, &gt; 1 and &lt; 3</span>] =&gt; <span class="hljs-literal">true</span>,
        _ =&gt; <span class="hljs-literal">false</span>
    };
    result.Should().BeTrue();
}
</code></pre>
<hr />
<h2 id="heading-level-up-your-patterns">Level Up Your Patterns</h2>
<p><strong><em>List Patterns</em></strong> are recursive and can contain any combination of nested <strong><em>Patterns.</em></strong> Combining all the available patterns, we can thoroughly inspect the content of a sequence and enforce positional relationships within the sequence. If we have a set of objects, say <code>Person</code></p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">sealed</span> record <span class="hljs-title">Person</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> Name, <span class="hljs-keyword">int</span> Age</span>)</span>;
</code></pre>
<p>For us to express the idea that <strong>Josh</strong> must be <em>second</em> in our sequence we can write the following pattern</p>
<pre><code class="lang-csharp">[<span class="hljs-meta">Fact</span>]
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Match_Positional_Pattern</span>(<span class="hljs-params"></span>)</span>
{
    <span class="hljs-keyword">var</span> seq = <span class="hljs-keyword">new</span> Person[]
    {
    <span class="hljs-keyword">new</span>(<span class="hljs-string">"Mike"</span>, <span class="hljs-number">23</span>),
    <span class="hljs-keyword">new</span>(<span class="hljs-string">"Josh"</span>, <span class="hljs-number">67</span>)
    };
    <span class="hljs-keyword">var</span> result = seq <span class="hljs-keyword">switch</span>
    {
        [<span class="hljs-meta">_, (<span class="hljs-meta-string">"Josh"</span>, _)</span>] =&gt; <span class="hljs-literal">true</span>,
        _ =&gt; <span class="hljs-literal">false</span>
    };
    result.Should().BeTrue();
}
</code></pre>
<p>We can even express a <strong><em>Property Pattern</em></strong></p>
<pre><code class="lang-csharp">[<span class="hljs-meta">Fact</span>]
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Match_Property_Pattern</span>(<span class="hljs-params"></span>)</span>
{
    <span class="hljs-keyword">var</span> seq = <span class="hljs-keyword">new</span> Person[]
    {
    <span class="hljs-keyword">new</span>(<span class="hljs-string">"Mike"</span>, <span class="hljs-number">23</span>),
    <span class="hljs-keyword">new</span>(<span class="hljs-string">"Josh"</span>, <span class="hljs-number">67</span>)
    };
    <span class="hljs-keyword">var</span> result = seq <span class="hljs-keyword">switch</span>
    {
        [<span class="hljs-meta">_, { Age: &gt; 18 }</span>] =&gt; <span class="hljs-literal">true</span>,
        _ =&gt; <span class="hljs-literal">false</span>
    };
    result.Should().BeTrue();
}
</code></pre>
<p>And don't forget we can capture sequence elements in our <code>switch expression</code></p>
<pre><code class="lang-csharp">[<span class="hljs-meta">Fact</span>]
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Match_Var_Pattern</span>(<span class="hljs-params"></span>)</span>
{
    <span class="hljs-keyword">var</span> seq = <span class="hljs-keyword">new</span> Person[]
    {
    <span class="hljs-keyword">new</span>(<span class="hljs-string">"Mike"</span>, <span class="hljs-number">23</span>),
    <span class="hljs-keyword">new</span>(<span class="hljs-string">"Josh"</span>, <span class="hljs-number">67</span>)
    };
    <span class="hljs-keyword">var</span> result = seq <span class="hljs-keyword">switch</span>
    {
        [<span class="hljs-meta">_, var person</span>] =&gt; person,
        _ =&gt; <span class="hljs-literal">null</span>
    };
    result.Should().BeEquivalentTo(seq[<span class="hljs-number">1</span>]);
}
</code></pre>
<h1 id="heading-imagination-is-the-limit">Imagination is the limit!</h1>
<p>Don't stop here! These new powerful patterns are just aching to be leveraged in new and brilliant ways. The C# team keeps delivering powerful advancements to an already incredible language.</p>
<p><strong><em>Please share your creativity in the comments, what can you do with these patterns!?</em></strong></p>
]]></content:encoded></item><item><title><![CDATA[AsyncMediator Series - Part 2]]></title><description><![CDATA[Welcome Back! 👋
So glad you made it back for Part 2, in Part 1: Broadcast Messaging - In Memory we created the implementation of something called Flow. Which is simply the broadcast of messages across many Consumers from many Originators leveraging ...]]></description><link>https://concurrentflows.com/asyncmediator-series-part-2</link><guid isPermaLink="true">https://concurrentflows.com/asyncmediator-series-part-2</guid><category><![CDATA[C#]]></category><category><![CDATA[messaging]]></category><category><![CDATA[mediator]]></category><category><![CDATA[dotnet]]></category><category><![CDATA[decoupling]]></category><dc:creator><![CDATA[Joshua Steward]]></dc:creator><pubDate>Tue, 15 Nov 2022 23:42:30 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1665196187815/0YRtkg2WZ.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-welcome-back">Welcome Back! 👋</h1>
<p>So glad you made it back for Part 2, in Part 1: <a target="_blank" href="https://concurrentflows.hashnode.dev/broadcast-messaging-in-memory">Broadcast Messaging - In Memory</a> we created the implementation of something called <em>Flow</em>. Which is simply the broadcast of messages across many <em>Consumers</em> from many <em>Originators</em> leveraging TPL Dataflow internally.</p>
<h2 id="heading-towards-our-asyncmediator">Towards our AsyncMediator</h2>
<p>Our next step is to introduce the concept of <em>Message Completion</em>. This means the <em>Consumer</em> indicates whether it has <code>Completed</code> processing or <code>Failed</code> to process the received message. We want to maintain the broadcast capabilities of the <em>Flow</em> and that feature will drive us away from our TPL Dataflow implementation.</p>
<p>What we'll gain is the ability to dynamically on board <em>Consumers</em> and have a greater fine-grained control of all <em>Consumers</em>. Additionally, this will permit the ability to support <code>Queries</code> and not limit us to <code>Commands</code></p>
<h1 id="heading-building-a-new-flow">Building a new flow</h1>
<p>First, let's lay out some requirments of our new implemtntation:</p>
<ul>
<li><p><strong>Must</strong> allow many <em>Originators</em></p>
</li>
<li><p><strong>Must</strong> allow many <em>Consumers</em></p>
</li>
<li><p><strong>Must</strong> allow <em>Sinks</em> to detach from <em>Source</em></p>
</li>
<li><p><strong>Must</strong> only <em>Complete</em> an <code>Envelope</code> when all <em>Consumers</em> finish</p>
</li>
</ul>
<h2 id="heading-our-library-api">Our Library Api</h2>
<p>We want this new flow to be easy and simple to consume. Ideally we should have a simple registration and well known interfaces to consume. To start with our registration should look something like this, along with a sample <em>Message</em>.</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> IServiceCollection <span class="hljs-title">AddMsgChannel</span>&lt;<span class="hljs-title">TPayload</span>&gt;(<span class="hljs-params"><span class="hljs-keyword">this</span> IServiceCollection services</span>)
    <span class="hljs-keyword">where</span> TPayload : notnull

<span class="hljs-keyword">public</span> <span class="hljs-keyword">sealed</span> record <span class="hljs-title">Message</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> Id</span>)</span>;
</code></pre>
<p>We intend to provide consumers of the library a simple interface to interact with. For example, the <em>Originator</em> of <em>Messages</em> would look something like this:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">sealed</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Originator</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IChannelSource&lt;Message&gt; source;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Originator</span>(<span class="hljs-params">IChannelSource&lt;Message&gt; source</span>)</span>
        =&gt; <span class="hljs-keyword">this</span>.source = source;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> ValueTask <span class="hljs-title">ProduceManyAsync</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> count, CancellationToken cancelToken</span>)</span>
    {
        <span class="hljs-keyword">var</span> messages = Enumerable.Range(<span class="hljs-number">0</span>, count)
            .Select(i =&gt; <span class="hljs-keyword">new</span> Message(i).ToEnvelope());
        <span class="hljs-keyword">var</span> sending = messages.Select(<span class="hljs-keyword">async</span> msg =&gt; <span class="hljs-keyword">await</span> source.SendAsync(msg));
        <span class="hljs-keyword">await</span> Task.WhenAll(sending);
    }
}
</code></pre>
<p>And, a simple <em>Consumer</em> of <em>Messages</em> would look like this:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">sealed</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Consumer</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IChannelSink&lt;Message&gt; sink;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Consumer</span>(<span class="hljs-params">IChannelSink&lt;Message&gt; sink</span>)</span> 
        =&gt; <span class="hljs-keyword">this</span>.sink = sink;

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;IEnumerable&lt;Message&gt;&gt; CollectAllAsync(CancellationToken cancelToken)
    {
        <span class="hljs-keyword">var</span> <span class="hljs-keyword">set</span> = <span class="hljs-keyword">new</span> List&lt;Message&gt;();
        <span class="hljs-keyword">try</span>
        {

            <span class="hljs-keyword">await</span> <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> envelope <span class="hljs-keyword">in</span> sink.ConsumeAsync(cancelToken))
                <span class="hljs-keyword">set</span>.Add(envelope.Payload);
        }
        <span class="hljs-keyword">catch</span> (OperationCanceledException)
        { <span class="hljs-comment">/*We're Done*/</span> }
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">set</span>;
    }
}
</code></pre>
<h2 id="heading-guiding-test">Guiding Test</h2>
<p>All that we need to expose is the simple diametrical interfaces; <code>Sink</code> &amp; <code>Source</code>. With these and our requirements in mind, we can write a test and let that drive and affirm our implementation.</p>
<pre><code class="lang-csharp">[<span class="hljs-meta">Fact</span>]
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">Source_BroadcastsTo_AllConsumers</span>(<span class="hljs-params"></span>)</span>
{
    <span class="hljs-keyword">var</span> provider = <span class="hljs-keyword">new</span> ServiceCollection()
        .AddMsgChannel&lt;Message&gt;()
        .AddTransient&lt;Originator&gt;()
        .AddTransient&lt;Consumer&gt;()
        .BuildServiceProvider();

    <span class="hljs-keyword">var</span> originator1 = provider.GetRequiredService&lt;Originator&gt;();
    <span class="hljs-keyword">var</span> originator2 = provider.GetRequiredService&lt;Originator&gt;();
    <span class="hljs-keyword">var</span> consumer1 = provider.GetRequiredService&lt;Consumer&gt;();
    <span class="hljs-keyword">var</span> consumer2 = provider.GetRequiredService&lt;Consumer&gt;();
    originator1.Should().NotBe(originator2);
    consumer1.Should().NotBe(consumer2);        

    <span class="hljs-keyword">var</span> count = <span class="hljs-number">100</span>;
    <span class="hljs-keyword">using</span> <span class="hljs-keyword">var</span> cts = <span class="hljs-keyword">new</span> CancellationTokenSource();
    <span class="hljs-keyword">var</span> consume1 = consumer1.CollectAllAsync(cts.Token);
    <span class="hljs-keyword">var</span> consume2 = consumer2.CollectAllAsync(cts.Token);
    <span class="hljs-keyword">var</span> sending1 = originator1.ProduceManyAsync(count, cts.Token);
    <span class="hljs-keyword">var</span> sending2 = originator2.ProduceManyAsync(count, cts.Token);

    <span class="hljs-keyword">await</span> Task.WhenAll(sending1, sending2);
    cts.Cancel();
    <span class="hljs-keyword">var</span> set1 = <span class="hljs-keyword">await</span> consume1;
    <span class="hljs-keyword">var</span> set2 = <span class="hljs-keyword">await</span> consume2;

    set1.Should().HaveCount(count * <span class="hljs-number">2</span>);
    set2.Should().HaveCount(count * <span class="hljs-number">2</span>);
    set1.Should().BeEquivalentTo(set2);
}
</code></pre>
<p>Our test sets up the Dependency Registration, then creates two of each <em>Producer</em> and <em>Consumers</em>. We assert that each instance is unique and then kick off our action. We trigger the <em>Consumers</em> to start listening and trigger the <em>Producers</em> to start sending a preset count of <em>Messages</em>. Once our <em>Producers</em> complete, we trigger the <code>CancellationToken</code> to stop our <em>Consumers</em>. After awaiting the consumption <code>Tasks</code> we can assert that each <em>Consumer</em> has received all <em>Messages</em>, double the original count, since we have two <em>Producers</em>. Finally, we assert that both sets of <em>Messages</em> are equal, indicating that we did multicast from each <em>Prodcer</em> to every <em>Consumer</em>.</p>
<p>To beign our implementation we look to the humble <code>Envelope</code>. This will be the container and carrier of our <code>Payload</code> and serve as the conduit for various utilities.</p>
<h1 id="heading-the-envelope">The Envelope</h1>
<p>The first piece we need to extend is the <code>Envelope</code>. The <code>Envelope</code> will be the item that allows us to communicate an Ack/Nack back to the <em>Originator</em>.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">record</span> <span class="hljs-title">Envelope</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">virtual</span> <span class="hljs-keyword">string</span> EnvelopeId =&gt; <span class="hljs-string">$"<span class="hljs-subst">{GetHashCode()}</span>"</span>;
}
</code></pre>
<p>This provides our base and gives us an overridable <code>EnvelopeId</code> defaulting to the hash code of the <code>record</code> itself.</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">sealed</span> record <span class="hljs-title">Envelope</span>&lt;<span class="hljs-title">TPayload</span>&gt;(<span class="hljs-params">
    TPayload Payload,
    TaskCompletionSource TaskSource,
    Task Execution</span>)
    : Envelope
    <span class="hljs-keyword">where</span> TPayload : notnull</span>
{
    <span class="hljs-keyword">private</span> TaskCompletionSource TaskSource { <span class="hljs-keyword">get</span>; } = TaskSource;
    <span class="hljs-keyword">private</span> Task Execution { <span class="hljs-keyword">get</span>; } = Execution;

    <span class="hljs-keyword">public</span> Exception? Failure { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">private</span> <span class="hljs-keyword">set</span>; }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Complete</span>(<span class="hljs-params"></span>)</span>
        =&gt; TaskSource.TrySetResult();

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Fail</span>(<span class="hljs-params">Exception exception</span>)</span>
    {
        TaskSource.TrySetException(exception);
        Failure = exception;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> TaskAwaiter <span class="hljs-title">GetAwaiter</span>(<span class="hljs-params"></span>)</span>
        =&gt; Execution.GetAwaiter();
}
</code></pre>
<p>The first derivation <code>Envelope</code> carries a <em>Payload</em>, that is, any object of type <code>TPayload</code>. It exposes two methods to <code>Complete</code>: <strong>ACK</strong>, or <code>Fail</code>: <strong>NACK</strong>. Next, it privately holds a <code>TaskCompletionSource</code> that is used to manage the completion of the <code>Envelope</code>. Finally, a private <code>Task</code>, whose <code>Awaiter</code> is exposed, this allows the <code>Envelope</code> to be awaited by an <em>Originator</em>.</p>
<h2 id="heading-task-amp-taskcompletionsource">Task &amp; TaskCompletionSource</h2>
<p>The execution <code>Task</code> represents the abstract idea of any work necessary to process the <code>Envelope</code>. Note that the work to process the <em>Message</em> is not tied to the <code>Task</code> directly. We're <strong><em>not awaiting any Consumer</em></strong>. Instead, we're maintaining an outstanding future that can be finalized by a <code>Complete</code> or <code>Fail</code> method.</p>
<p>The <code>TaskCompletionSource</code> is used to signal that the <code>Task</code> has finished. <code>Conmplete</code> sets the results as successful. <code>Fail</code> takes an <code>Exception</code> indicating that processing failed. However, the <code>Exception</code> won't be propagated via an <code>await</code>. We don't want the <em>Originator</em>, who may be awaiting the <code>Envelope</code>, to pop an <code>Exception</code> off the <code>Task</code>. Instead, we use the pattern of a nullable <code>Exception</code> to expose failure and encourage null propagation.</p>
<h2 id="heading-packaging-an-envelope">Packaging an Envelope</h2>
<p>To pack this all up we first stuff in the <code>Payload</code> and create our <code>TaskCompletionSource</code>. We'll wrap this together with a timeout and async callbacks for <code>onComplete</code> and <code>onFailure</code>.</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-title">Envelope</span>&lt;<span class="hljs-title">TPayload</span>&gt; <span class="hljs-title">ToEnvelope</span>&lt;<span class="hljs-title">TPayload</span>&gt;(<span class="hljs-params">
    <span class="hljs-keyword">this</span> TPayload payload,
    TimeSpan timeout,
    Func&lt;Task&gt; onCompleted,
    Func&lt;Task&gt; onFailure</span>)
    <span class="hljs-keyword">where</span> TPayload : notnull</span>
    =&gt; <span class="hljs-keyword">new</span> TaskCompletionSource()
        .CreateEnvelope(payload, timeout, onCompleted, onFailure);
</code></pre>
<p>Next, our <code>TaskCompletionSource</code> is used to form an <code>ExecutionMontior</code>. The job of the monitor is to maintain the timeout and execute either <code>onCompleted</code> or <code>onFailure</code></p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-title">Envelope</span>&lt;<span class="hljs-title">TPayload</span>&gt; <span class="hljs-title">CreateEnvelope</span>&lt;<span class="hljs-title">TPayload</span>&gt;(<span class="hljs-params">
    <span class="hljs-keyword">this</span> TaskCompletionSource taskSource,
    TPayload payload,
    TimeSpan timeout,
    Func&lt;Task&gt; onCompleted,
    Func&lt;Task&gt; onFailure</span>)
    <span class="hljs-keyword">where</span> TPayload : notnull</span>
    =&gt; <span class="hljs-keyword">new</span> Envelope&lt;TPayload&gt;(
        Payload: payload,
        TaskSource: taskSource,
        Execution: taskSource.CreateExecutionMonitor(timeout, onCompleted, onFailure));

<span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> Task <span class="hljs-title">CreateExecutionMonitor</span>(<span class="hljs-params"><span class="hljs-keyword">this</span> TaskCompletionSource source,
    TimeSpan timeout,
    Func&lt;Task&gt; onCompleted,
    Func&lt;Task&gt; onFailure</span>)</span>
{
    <span class="hljs-keyword">return</span> AsyncExecutionMonitor(source.Task, timeout, onCompleted, onFailure);

    <span class="hljs-function"><span class="hljs-keyword">async</span> Task <span class="hljs-title">AsyncExecutionMonitor</span>(<span class="hljs-params">
        Task completion,
        TimeSpan timeout,
        Func&lt;Task&gt; onCompleted,
        Func&lt;Task&gt; onFailure</span>)</span>
    {
        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">await</span> completion.TryWaitAsync(timeout))
            <span class="hljs-keyword">await</span> onCompleted();
        <span class="hljs-keyword">else</span>
            <span class="hljs-keyword">await</span> onFailure();
    }
}

<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">async</span> Task&lt;<span class="hljs-keyword">bool</span>&gt; <span class="hljs-title">TryWaitAsync</span>(<span class="hljs-params"><span class="hljs-keyword">this</span> Task task, TimeSpan timeout</span>)</span>
{
    <span class="hljs-keyword">await</span> Task.WhenAny(task, Task.Delay(timeout));
    <span class="hljs-keyword">return</span> task.IsCompletedSuccessfully;
}
</code></pre>
<p>The async monitor applies a global timeout to the future we're maintaining for the processing work. We cannot <em>Cancel</em> the work when the timeout has expired. This is a direct consequence of not having direct control, coupling, to the work being performed. The best we can do in this position is to <em>Fail</em> on our side and move on.</p>
<p>Within <code>TryWaitAsync</code> we can see how the <code>TrySetException</code> from within the <code>Envelope</code> is rerouted into a bool consequence. It simply leverages <code>WhenAny</code> and only considers if the <code>Task</code> was successful. We know that any exception captured by the call to <code>Fail(ex)</code> sets the failure on the <code>Envelope</code> itself.</p>
<h2 id="heading-completion">Completion</h2>
<p>Now with <code>Envelope&lt;TPayload&gt;</code> in hand.</p>
<p>Think for a moment; How, within our broadcast framework, do we determine if a <em>Message</em> is <em>Complete</em>? We can't simply say the <em>Originating</em> message is <em>Complete</em> when only one <em>Consumer</em> finishes. And what happens if 1 out of 20 <em>Consumers</em> fail? A reasonable default would be to wait for all <em>Consumers</em> and assume failure if any single <em>Message</em> fails. This follows the pattern of at-most-once delivery, although, we could extend to dedicated retrying of failures and more complex strategies. Now, recall we have a dynamic <em>Consumer Set</em> that we don't have direct knowledge of, so how do we manage the broadcast?</p>
<p>The <a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.dataflow.broadcastblock-1?view=net-6.0"><code>BroadcastBlock</code></a> we used for our original implementation in <a target="_blank" href="https://concurrentflows.hashnode.dev/broadcast-messaging-in-memory">Part 1</a> doesn't expose it's <em>Consumers</em> in any way. We don't see how many there are, nor even if all <em>Consumers</em> have been offered the <code>Envelope</code>. We'll need more control for this and that's where we'll leverage <a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/core/extensions/channels"><code>Channels</code></a></p>
<h1 id="heading-channelsource">ChannelSource</h1>
<p>To control our broadcast we need knowledge and control over "Subscribers"/<em>Consumers</em> of our <code>Source</code>. The first step is to create our own variant of the TPL Dataflow <code>Link</code>. This is a structure representing the connection of a <code>Source</code> and <code>Sink</code>.</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> record <span class="hljs-keyword">struct</span> <span class="hljs-title">SinkLink</span>(<span class="hljs-params">Guid LinkId</span>) : IDisposable</span>
{
    <span class="hljs-keyword">private</span> Action&lt;Guid&gt;? unlink = <span class="hljs-keyword">default</span>;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">bool</span> disposed = <span class="hljs-literal">false</span>;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">SinkLink</span>(<span class="hljs-params">Guid linkId, Action&lt;Guid&gt; unlink</span>)
        : <span class="hljs-title">this</span>(<span class="hljs-params">linkId</span>)</span>
        =&gt; <span class="hljs-keyword">this</span>.unlink = unlink;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Dispose</span>(<span class="hljs-params"></span>)</span>
    {
        Dispose(disposing: <span class="hljs-literal">true</span>);
        GC.SuppressFinalize(<span class="hljs-keyword">this</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Dispose</span>(<span class="hljs-params"><span class="hljs-keyword">bool</span> disposing</span>)</span>
    {
        <span class="hljs-keyword">if</span> (disposing &amp;&amp; !disposed)
            unlink?.Invoke(LinkId);
        disposed = <span class="hljs-literal">true</span>;
        unlink = <span class="hljs-literal">null</span>;
    }
}
</code></pre>
<p>Our <code>SinkLink</code> is identifiable by its <code>LinkId</code> and it holds a reference that allows it to <code>Unlink</code> from the source via its <code>LinkId</code>.</p>
<p>Next, we'll capture the concept of many outgoing <em>Messages</em> in the form of an <code>Outbox</code>. This allows us to maintain record of all <em>Messages</em> broadcast and when they have <em>Completed</em></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">IOutbox</span>&lt;<span class="hljs-title">TPayload</span>&gt; <span class="hljs-keyword">where</span> <span class="hljs-title">TPayload</span> : <span class="hljs-title">notnull</span>
{
    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">Complete</span>(<span class="hljs-params"></span>)</span>;
    <span class="hljs-function">Envelope&lt;TPayload&gt; <span class="hljs-title">GetEnvelope</span>(<span class="hljs-params"></span>)</span>;
}
</code></pre>
<p>This <code>Outbox</code> is intended to be created, then <em>Messages</em> submitted and finally <code>Completed</code>.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">internal</span> <span class="hljs-keyword">sealed</span> <span class="hljs-keyword">class</span> <span class="hljs-title">EnvelopeOutbox</span>&lt;<span class="hljs-title">TPayload</span>&gt; : <span class="hljs-title">IOutbox</span>&lt;<span class="hljs-title">TPayload</span>&gt;
    <span class="hljs-keyword">where</span> <span class="hljs-title">TPayload</span> : <span class="hljs-title">notnull</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> Envelope&lt;TPayload&gt; originator;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> Action&lt;Guid&gt; destructor;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ConcurrentDictionary&lt;Guid, Envelope&lt;TPayload&gt;&gt; pool = <span class="hljs-keyword">new</span>();
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ConcurrentBag&lt;Exception&gt; failures = <span class="hljs-keyword">new</span>();

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">volatile</span> <span class="hljs-keyword">int</span> leaseCount = <span class="hljs-number">0</span>;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">volatile</span> <span class="hljs-keyword">bool</span> complete = <span class="hljs-literal">false</span>;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">EnvelopeOutbox</span>(<span class="hljs-params">
        Envelope&lt;TPayload&gt; originator,
        Action&lt;Guid&gt; destructor</span>)</span>
    {
        <span class="hljs-keyword">this</span>.originator = originator;
        <span class="hljs-keyword">this</span>.destructor = destructor;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Complete</span>(<span class="hljs-params"></span>)</span>
        =&gt; complete = <span class="hljs-literal">true</span>;

    <span class="hljs-function"><span class="hljs-keyword">public</span> Envelope&lt;TPayload&gt; <span class="hljs-title">GetEnvelope</span>(<span class="hljs-params"></span>)</span>
    {
        Interlocked.Increment(<span class="hljs-keyword">ref</span> leaseCount);

        <span class="hljs-keyword">var</span> id = Guid.NewGuid();
        <span class="hljs-keyword">var</span> envelope = originator.Payload.ToEnvelope(
            TimeSpan.FromSeconds(<span class="hljs-number">30</span>),
            () =&gt; EnvelopeDestructorAsync(id),
            () =&gt; EnvelopeDestructorAsync(id));

        pool[id] = envelope;
        <span class="hljs-keyword">return</span> envelope;
    }

    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">EnvelopeDestructorAsync</span>(<span class="hljs-params">Guid id</span>)</span>
    {
        Interlocked.Decrement(<span class="hljs-keyword">ref</span> leaseCount);

        <span class="hljs-keyword">var</span> envelope = pool[id];
        failures.MaybeAdd(envelope?.Failure);

        <span class="hljs-keyword">if</span> (!ReadyForClosure) <span class="hljs-keyword">return</span>;

        <span class="hljs-keyword">await</span> CloseOutPool(id);
    }

    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">CloseOutPool</span>(<span class="hljs-params">Guid id</span>)</span>
    {
        <span class="hljs-keyword">await</span> Task.WhenAll(pool.Select(<span class="hljs-keyword">async</span> e =&gt; <span class="hljs-keyword">await</span> e.Value));

        <span class="hljs-keyword">if</span> (failures.Any())
            originator.Fail(<span class="hljs-keyword">new</span> AggregateException(failures));
        <span class="hljs-keyword">else</span>
            originator.Complete();

        destructor(id);
    }

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">bool</span> ReadyForClosure
        =&gt; leaseCount &lt;= <span class="hljs-number">0</span> &amp;&amp; complete;
}
</code></pre>
<p>From this implementation we can see several things:</p>
<ol>
<li><p>Creation is dependent on an <em>Originating Message</em> and a <code>Destructor</code> to handle the finalization of the <code>Outbox</code></p>
</li>
<li><p>Each time a <em>Message</em> is requested we increment the internal <code>leaseCount</code></p>
</li>
<li><p>The outgoing <em>Messages</em> are connected such that they are destructed, decrement the <code>leaseCount</code> and give us an opportunity to <em>Close</em> the <code>Outbox</code> via <code>EnvelopeDestructorAsync</code></p>
</li>
<li><p>Once the <code>Outbox</code> is <em>Complete</em> and the <code>leaseCount</code> reaches zero we aggregate any <code>Exceptions</code> calling <code>Complete</code> or <code>Fail</code> on the <em>Originator's Message</em></p>
</li>
<li><p>Finally, the <code>Source</code> provided <code>Outbox Destructor</code> can be executed.</p>
</li>
</ol>
<p>All of this allows our <code>Source</code> to broadcast and maintain knowledge of all outgoing <em>Messages</em>. From the previous we can see we need to define two <em>Factory Delegates</em></p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">delegate</span> <span class="hljs-title">IChannelSink</span>&lt;<span class="hljs-title">TPayload</span>&gt; <span class="hljs-title">SinkFactory</span>&lt;<span class="hljs-title">TPayload</span>&gt;(<span class="hljs-params"></span>)
    <span class="hljs-keyword">where</span> TPayload : notnull</span>;

<span class="hljs-function"><span class="hljs-keyword">delegate</span> <span class="hljs-title">IOutbox</span>&lt;<span class="hljs-title">TPayload</span>&gt; <span class="hljs-title">OutboxFactory</span>&lt;<span class="hljs-title">TPayload</span>&gt;(<span class="hljs-params">
    Envelope&lt;TPayload&gt; originator,
    Action&lt;Guid&gt; destructor</span>)
    <span class="hljs-keyword">where</span> TPayload : notnull</span>;
</code></pre>
<p>First, the <code>SinkFactory</code> will be responsible for creating a new <code>ChannelSink&lt;TPayload&gt;</code>. We can register this delegate and inject it if we ever find ourselves dynamically creating new <em>Consumers</em>. But for now, we'll implement it within our <code>Source</code>. Secondly, we have the <code>OutboxFactory</code> that creates an <code>Outbox</code> each time we need to broadcast a <em>Message</em>.</p>
<p>The advantage of having these delegates is that it allows us to place their implementation close to the source of their use. The <code>SinkFactory</code> will be held within the <code>ChannelSource</code>, allowing us to place the new <code>Sink</code> within the collection of targets held by the <code>Source</code>. The <code>OutboxFactory</code>, while not entirely necessary, is a simple abstraction of the <code>Outbox</code> constructor that allows us to create one on demand and mock its implementation for testing.</p>
<h2 id="heading-diving-in">Diving in</h2>
<p>Now let's dive right into the implementation of the <code>Source</code>, we have:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">internal</span> <span class="hljs-keyword">sealed</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ChannelSource</span>&lt;<span class="hljs-title">TPayload</span>&gt;
    : <span class="hljs-title">IChannelSource</span>&lt;<span class="hljs-title">TPayload</span>&gt;,
    <span class="hljs-title">ILinkableSource</span>&lt;<span class="hljs-title">TPayload</span>&gt;
    <span class="hljs-keyword">where</span> <span class="hljs-title">TPayload</span> : <span class="hljs-title">notnull</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> OutboxFactory&lt;TPayload&gt; factory;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ConcurrentDictionary&lt;Guid, ChannelWriter&lt;Envelope&lt;TPayload&gt;&gt;&gt; channels = <span class="hljs-keyword">new</span>();
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ConcurrentDictionary&lt;Guid, IOutbox&lt;TPayload&gt;&gt; outboundMsgs = <span class="hljs-keyword">new</span>();

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">ChannelSource</span>(<span class="hljs-params">OutboxFactory&lt;TPayload&gt; outboxFactory</span>)</span>
        =&gt; <span class="hljs-keyword">this</span>.factory = outboxFactory;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> ValueTask&lt;<span class="hljs-keyword">bool</span>&gt; <span class="hljs-title">SendAsync</span>(<span class="hljs-params">Envelope&lt;TPayload&gt; envelope, CancellationToken cancelToken = <span class="hljs-keyword">default</span></span>)</span>
    {
        cancelToken.ThrowIfCancellationRequested();
        <span class="hljs-keyword">var</span> outboxId = Guid.NewGuid();
        <span class="hljs-keyword">var</span> outbox = factory(envelope, (id) =&gt; outboundMsgs.Remove(id, <span class="hljs-keyword">out</span> _));
        outboundMsgs.TryAdd(outboxId, outbox);
        <span class="hljs-keyword">var</span> writers = channels.Values;

        <span class="hljs-keyword">var</span> writing = writers.Select(<span class="hljs-keyword">async</span> writer =&gt;
        {
            <span class="hljs-keyword">await</span> Task.Yield();
            <span class="hljs-keyword">var</span> outbound = outbox.GetEnvelope();
            <span class="hljs-keyword">return</span> writer.TryWrite(outbound);
        });
        outbox.Complete();
        <span class="hljs-keyword">var</span> results = <span class="hljs-keyword">await</span> Task.WhenAll(writing);

        <span class="hljs-keyword">return</span> results.All(s =&gt; s);
    }

    <span class="hljs-keyword">public</span> SinkFactory&lt;TPayload&gt; SinkFactory
        =&gt; () =&gt;
        {
            <span class="hljs-keyword">var</span> linkId = Guid.NewGuid();
            <span class="hljs-keyword">var</span> sinkLink = <span class="hljs-keyword">new</span> SinkLink(linkId, id =&gt; channels.Remove(id, <span class="hljs-keyword">out</span> _));
            <span class="hljs-keyword">var</span> channel = Channel.CreateUnbounded&lt;Envelope&lt;TPayload&gt;&gt;();
            channels.TryAdd(linkId, channel);
            <span class="hljs-keyword">var</span> channelSink = <span class="hljs-keyword">new</span> ChannelSink&lt;TPayload&gt;(channel, sinkLink);
            <span class="hljs-keyword">return</span> channelSink;
        };
}
</code></pre>
<p>Breaking this down we have two concurrent collections, each keyed with a UUID. The first, <code>channels</code> is dedicated to holding all the targets our <code>Source</code> is going to broadcast to. While <code>outboundMsgs</code> will maintain an <code>Outbox</code> for all <em>Messages</em> in flight</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ConcurrentDictionary&lt;Guid, ChannelWriter&lt;Envelope&lt;TPayload&gt;&gt;&gt; channels = <span class="hljs-keyword">new</span>();
<span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ConcurrentDictionary&lt;Guid, IOutbox&lt;TPayload&gt;&gt; outboundMsgs = <span class="hljs-keyword">new</span>();
</code></pre>
<p>Then we have an implementation of the factory delegate <code>SinkFactory&lt;TPayload&gt;</code>. This delegate implantation lives within the <code>Source</code> in order to link the new <code>Sink</code> to the <code>Source</code> via the <code>SinkLink</code>. Additionally, the destructor we pass enables removal of the target from the private set.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> SinkFactory&lt;TPayload&gt; SinkFactory
    =&gt; () =&gt;
    {
        <span class="hljs-keyword">var</span> linkId = Guid.NewGuid();
        <span class="hljs-keyword">var</span> sinkLink = <span class="hljs-keyword">new</span> SinkLink(linkId, id =&gt; channels.Remove(id, <span class="hljs-keyword">out</span> _));
        <span class="hljs-keyword">var</span> channel = Channel.CreateUnbounded&lt;Envelope&lt;TPayload&gt;&gt;();
        channels.TryAdd(linkId, channel);
        <span class="hljs-keyword">var</span> channelSink = <span class="hljs-keyword">new</span> ChannelSink&lt;TPayload&gt;(channel, sinkLink);
        <span class="hljs-keyword">return</span> channelSink;
    };
</code></pre>
<p>And finally, the real work is done within <code>SendAsync(..)</code>. First, we check the <code>cancelToken</code>. Then, we iterate through all targets. The syncronuous <code>TryWrite</code> is used since we know these targets are unbound <code>Sinks</code> and we've side stepped any idea of <code>Channel</code> completion. However, there's no need to wait for any single <code>TryWrite</code> so the operation yields to the iteration and we asyncronuously wait for all writes to complete. Finally, we return success or failure simply based on whether all writes were successful or not.</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> ValueTask&lt;<span class="hljs-keyword">bool</span>&gt; <span class="hljs-title">SendAsync</span>(<span class="hljs-params">
    Envelope&lt;TPayload&gt; envelope, 
    CancellationToken cancelToken = <span class="hljs-keyword">default</span></span>)</span>
{
    cancelToken.ThrowIfCancellationRequested();
    <span class="hljs-keyword">var</span> outboxId = Guid.NewGuid();
    <span class="hljs-keyword">var</span> outbox = factory(envelope, (id) =&gt; outboundMsgs.Remove(id, <span class="hljs-keyword">out</span> _));
    outboundMsgs.TryAdd(outboxId, outbox);
    <span class="hljs-keyword">var</span> writers = channels.Values;

    <span class="hljs-keyword">var</span> writing = writers.Select(<span class="hljs-keyword">async</span> writer =&gt;
    {
        <span class="hljs-keyword">await</span> Task.Yield();
        <span class="hljs-keyword">var</span> outbound = outbox.GetEnvelope();
        <span class="hljs-keyword">return</span> writer.TryWrite(outbound);
    });
    outbox.Complete();
    <span class="hljs-keyword">var</span> results = <span class="hljs-keyword">await</span> Task.WhenAll(writing);

    <span class="hljs-keyword">return</span> results.All(s =&gt; s);
}
</code></pre>
<h3 id="heading-well-that-was-easy">💥Well that was easy 🤣</h3>
<h1 id="heading-channelsink">ChannelSink</h1>
<p>The last core piece of Part 2; the <code>ChannelSink</code>. A much simpler implementation, all we need to do is continuously read from the <code>Channel</code> and handle a standard call to <code>Dispose</code>.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">internal</span> <span class="hljs-keyword">sealed</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ChannelSink</span>&lt;<span class="hljs-title">TPayload</span>&gt;
    : <span class="hljs-title">IChannelSink</span>&lt;<span class="hljs-title">TPayload</span>&gt;,
    <span class="hljs-title">IDisposable</span>
    <span class="hljs-keyword">where</span> <span class="hljs-title">TPayload</span> : <span class="hljs-title">notnull</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ChannelReader&lt;Envelope&lt;TPayload&gt;&gt; reader;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IDisposable sinkLink;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">bool</span> disposed = <span class="hljs-literal">false</span>;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">ChannelSink</span>(<span class="hljs-params">
        ChannelReader&lt;Envelope&lt;TPayload&gt;&gt; reader,
        IDisposable sinkLink</span>)</span>
    {
        <span class="hljs-keyword">this</span>.reader = reader;
        <span class="hljs-keyword">this</span>.sinkLink = sinkLink;
    }

    <span class="hljs-keyword">public</span> IAsyncEnumerable&lt;Envelope&lt;TPayload&gt;&gt; ConsumeAsync(CancellationToken cancelToken = <span class="hljs-keyword">default</span>)
        =&gt; reader.ReadAllAsync(cancelToken);

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Dispose</span>(<span class="hljs-params"></span>)</span>
    {
        Dispose(disposing: <span class="hljs-literal">true</span>);
        GC.SuppressFinalize(<span class="hljs-keyword">this</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Dispose</span>(<span class="hljs-params"><span class="hljs-keyword">bool</span> disposing</span>)</span>
    {
        <span class="hljs-keyword">if</span> (!disposed &amp;&amp; disposing)
            sinkLink.Dispose();
        disposed = <span class="hljs-literal">true</span>;
    }
}
</code></pre>
<h1 id="heading-registration-i-didnt-forget">Registration - I didn't forget</h1>
<p>Of course we can't forget the full implementation of our <code>IServiceCollection</code> extension</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> IServiceCollection <span class="hljs-title">AddMsgChannel</span>&lt;<span class="hljs-title">TPayload</span>&gt;(<span class="hljs-params"><span class="hljs-keyword">this</span> IServiceCollection services</span>)
    <span class="hljs-keyword">where</span> TPayload : notnull</span>
    =&gt; services
        .SetSingleton&lt;OutboxFactory&lt;TPayload&gt;&gt;(_
        =&gt; (originator, destructor)
            =&gt; <span class="hljs-keyword">new</span> EnvelopeOutbox&lt;TPayload&gt;(originator, destructor))
        .SetSingleton&lt;SinkFactory&lt;TPayload&gt;&gt;(sp =&gt;
        {
            <span class="hljs-keyword">var</span> source = sp.GetRequiredService&lt;IChannelSource&lt;TPayload&gt;&gt;();
            <span class="hljs-keyword">var</span> linkable = source <span class="hljs-keyword">as</span> ILinkableSource&lt;TPayload&gt;
                ?? <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentException(<span class="hljs-string">$"Source <span class="hljs-subst">{source.GetType().Name}</span> must be linkable"</span>, <span class="hljs-keyword">nameof</span>(source));
            <span class="hljs-keyword">return</span> linkable.SinkFactory;
        })
        .SetSingleton&lt;IChannelSource&lt;TPayload&gt;, ChannelSource&lt;TPayload&gt;&gt;()
        .AddTransient&lt;IChannelSink&lt;TPayload&gt;&gt;(sp =&gt; sp.GetRequiredService&lt;SinkFactory&lt;TPayload&gt;&gt;().Invoke());
</code></pre>
<h1 id="heading-closing-up">Closing Up</h1>
<p><a target="_blank" href="https://concurrentflows.hashnode.dev/broadcast-messaging-in-memory">Part 1</a> saw the most basic broadcast implementation. That got us on the right track splitting <em>Origination</em> and <em>Consumption</em>. Now, while maintaining separation, we've allowed the concept of <strong>Completion</strong> and <strong>Acknowledgement</strong> to be introduced. At the end of Part 2 we have succeeded in <strong><em>passing our test!</em></strong>. But more than that, we can now broadcast a message from multiple <em>Producers</em> to multiple <em>Consumers</em> and allow a positive or negative acknowledgement to flow back to the <em>Producer</em> via the <em>Originating Message</em></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1746728350241/81c68156-d072-4ea7-a961-9cc52440b3ba.png" alt class="image--center mx-auto" /></p>
<p>🤯Soo much cooler visually! But seriously with this in place, the next step towards our Async Mediator is a small jump and we're well on the right path.</p>
]]></content:encoded></item><item><title><![CDATA[SOLID Engineering Leadership]]></title><description><![CDATA[SOLID Engineering Leadership
Tranistioning from Engineer to Engineering Leader is a process full of opportunity. Opportunity to learn, grow, and to expand your knowledge base into domains you only scratched the surface of. It's also a process ready a...]]></description><link>https://concurrentflows.com/solid-engineering-leadership</link><guid isPermaLink="true">https://concurrentflows.com/solid-engineering-leadership</guid><category><![CDATA[leadership]]></category><category><![CDATA[engineering]]></category><category><![CDATA[empathy]]></category><dc:creator><![CDATA[Joshua Steward]]></dc:creator><pubDate>Mon, 07 Nov 2022 01:57:16 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1667785883113/kV_5vdNc8.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-solid-engineering-leadership">SOLID Engineering Leadership</h1>
<p>Tranistioning from Engineer to Engineering Leader is a process full of opportunity. Opportunity to learn, grow, and to expand your knowledge base into domains you only scratched the surface of. It's also a process ready and willing to teach a few hard lessons. One such lesson I learned was the application of Dependency Inversion as it pertains to leading a team of engineers.
There are several flavors, variations and interpretations of the Dependency Inversion Principle (DIP). The one I find most applicable here is</p>
<blockquote>
<ul>
<li>High-level modules should not import anything from low-level modules. Both should depend on abstractions (e.g., interfaces).</li>
<li>Abstractions should not depend on details. Details (concrete implementations) should depend on abstractions</li>
</ul>
</blockquote>
<h1 id="heading-how-is-that-relevant">How is that relevant?</h1>
<p>Sounds quite technical, doesn't it? This is clearly only applicable with my head down jamming out code and drinking Monster, right? Nope turns out this might be one of the most important principles you can apply to leadership.</p>
<p>The whole point of this principle is to avoid a tight coupling between implementation details and the value they yield. Between the value forming business logic and underlying technical concerns.</p>
<p>Viewed from a leadership perspective, our value building business logic lies with the product and/or feature we're trying to deliver. That's the critical <em>idea</em> the business wants to bring into being. The driver of this <em>idea</em> is the Product Owner/Manager, while its creation lies with the Engineer.</p>
<h2 id="heading-product-ownership">Product Ownership</h2>
<p>That nascent idea has intrinsic value outside of any technical implementation. It may well be implemented with an Archimedes' screw if that gets the job done. </p>
<h2 id="heading-engineering-rigor">Engineering Rigor</h2>
<p>As Software Engineers we implement the business logic with rigor and pragmatism. Software Engineers are 100% coupled to the details of the implementation and know its every nuance.</p>
<h1 id="heading-lesson-learned-207">Lesson Learned #207</h1>
<p>And this is the lesson I learned: The responsibility of Engineering Leadership is providing that abstraction between two concerns. The deep in the weeds, detail oriented Engineering implementation and that value driving, idea realizing Product Ownership. Each side of the coin depends on an abstraction of the other.</p>
<p>Living this Dependency Inversion means the leader is simultaneously</p>
<ol>
<li>Driven by the higher level Product Initiative</li>
<li>Provides the space and freedom to the engineering team to deliver</li>
</ol>
<p>These complimentary perspectives yield the compound title <strong><em>Engineering Leader</em></strong>. <strong>Lesson learned</strong>, maybe next time it'll be <strong><em>Liskov substitution principle</em></strong></p>
]]></content:encoded></item><item><title><![CDATA[AsyncMediator Series - Part 1]]></title><description><![CDATA[Inspiration

Origination executes distinctly from Consumption

From the beginning 🤔
The idea of a Mediator is generally the go to when we want to decouple a Request from its Processing. There's already some well established and widely used mediator ...]]></description><link>https://concurrentflows.com/asyncmediator-series-part-1</link><guid isPermaLink="true">https://concurrentflows.com/asyncmediator-series-part-1</guid><category><![CDATA[mediator]]></category><category><![CDATA[C#]]></category><category><![CDATA[messaging]]></category><category><![CDATA[message broker]]></category><category><![CDATA[dotnet]]></category><dc:creator><![CDATA[Joshua Steward]]></dc:creator><pubDate>Sat, 22 Oct 2022 12:24:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1665196170293/1NufEIh4O.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-inspiration">Inspiration</h1>
<blockquote>
<p><strong>Origination</strong> executes distinctly from <strong>Consumption</strong></p>
</blockquote>
<h2 id="heading-from-the-beginning"><em>From the beginning</em> 🤔</h2>
<p>The idea of a Mediator is generally the go to when we want to decouple a Request from its Processing. There's already some well established and widely used mediator packages e.g. <a target="_blank" href="https://github.com/jbogard/MediatR">MediatR</a>; <em>J. Bogard</em>, <a target="_blank" href="https://mayuanyang.github.io/Mediator.Net/">Mediator.NET</a>; <em>E. Ma</em>, etc.
These all quite well implement variations on the <a target="_blank" href="https://en.wikipedia.org/wiki/Mediator_pattern">Mediator Pattern...</a>👌. 
Largely we see these operating in process and not across the wire, with the exception of <a target="_blank" href="https://masstransit-project.com/usage/mediator.html">MassTransit - Mediator</a> of course, but we won't go there right now.😎
Additionally we can see many of the fundamental ideas presented within the <em><a target="_blank" href="https://blogs.cuttingedge.it/steven/posts/2011/meanwhile-on-the-query-side-of-my-architecture/">...Query Side</a> and <a target="_blank" href="https://blogs.cuttingedge.it/steven/posts/2011/meanwhile-on-the-command-side-of-my-architecture/">... Command Side</a> of my architecture;</em> <em>S. Deursen</em>, also of <a target="_blank" href="https://github.com/simpleinjector/SimpleInjector">Simple Injector</a> Rock Stardom 🎸</p>
<h2 id="heading-on-the-market-today">On the market today</h2>
<p>Right up front; I really enjoy both these libraries but ultimately I'd like to go another direction 🤔</p>
<p>First, let's take a closer look; all these options are quite feature rich, and support similar architectural patterns/styles.</p>
<ul>
<li><em>CQRS Style Patterns</em><ul>
<li><a target="_blank" href="https://github.com/jbogard/MediatR/wiki#requestresponse">Query/QueryHandler, Request/Response</a></li>
<li><a target="_blank" href="https://github.com/mayuanyang/Mediator.Net#sending-a-command-with-no-response">Command/CommandHandler</a></li>
</ul>
</li>
<li><em>Pub/Sub</em><ul>
<li><a target="_blank" href="https://github.com/jbogard/MediatR/wiki#notifications">Notifications</a></li>
<li><a target="_blank" href="https://github.com/mayuanyang/Mediator.Net#publishing-an-event">Publish Events</a></li>
</ul>
</li>
<li><em>Pipelines / Middleware / Behaviors</em><ul>
<li><a target="_blank" href="https://jimmybogard.com/sharing-context-in-mediatr-pipelines/">Pipelining &amp; Behaviors</a></li>
<li><a target="_blank" href="https://garywoodfine.com/how-to-use-mediatr-pipeline-behaviours/">Pipeline Behaviors</a></li>
<li><a target="_blank" href="https://github.com/mayuanyang/Mediator.Net#using-pipelines">Mediator.NET Pipelining</a></li>
<li><a target="_blank" href="https://github.com/mayuanyang/Mediator.Net#setting-up-middlewares">Mediator.NET Middleware</a></li>
</ul>
</li>
</ul>
<h2 id="heading-what-about-the-mediator">What about the Mediator?</h2>
<p>Traditionally, a Mediator represents a focal point between an <em>Originator</em> and one or many <em>Consumers</em>. This allows the <em>Originator</em> to avoid explicitly referring to or knowing about the <em>Consumers</em></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665074232468/89alJ7DoN.png" alt="Blog - Async Mediator - Typical Mediator.png" class="image--center mx-auto" /></p>
<p>The <em>Consumers</em> are typically conceptualized as <code>Handlers</code> of particular messages and can form <code>Pipelines</code> or chains. Each <code>Handler</code> playing a specific role in the choreography. Additional and complimentary concepts can be added with associated <code>Middleware</code> or <code>Behaviors</code>, etc. promoting some aspects of loose coupling. But the call from <em>Originator</em> to <code>Handler</code> is still synchronous with regard to its <code>Registration</code>. The <code>Registration</code> couples, albeit in the background, the <em>Originator</em> and the <em>Consumer</em> and both processes are tightly working together via the <code>Mediator</code>.</p>
<p>For instance <em>MediatR</em> holds a reference to all of its <em>Handlers</em> and dispatches associated <code>Requests</code> and/or <code>Notifications</code>. <em>Mediator.Net</em> has a nice abstraction in place; <code>Pipes</code> form its central core and you can even stream responses back via the receive pipeline. 
<code>💘IAsyncEnumerable</code>. However, all <code>Handlers</code> are registered and well known. Both of these methodologies yield a static topology.</p>
<p>These structures have the advantage when you want a response back from a particular request. But I'm not interested in call and response; receiving a message should yield another subsequent message and we'll leave any correlleation back to the origination to simply be implicit.</p>
<h1 id="heading-schema-driven-mediator">Schema Driven Mediator</h1>
<h2 id="heading-conceptually">Conceptually</h2>
<p>Conceptually what we're after is much the same as you'd find in a distributed messaging broker: Kafka, Pulsar, RabbitMQ, etc. With this in mind we'll split our message <strong>Origination</strong> entirely from it's <strong>Consumption</strong>; </p>
<blockquote>
<p>This is the key I want changed; <strong>Origination</strong> executes distinctly from <strong>Consumption</strong></p>
</blockquote>
<h2 id="heading-architectural-objectives">Architectural Objectives</h2>
<h3 id="heading-primary-goals">Primary Goals</h3>
<p>Fundamentally we want an entirely decoupled architecture; the only shared knowledge should be the message <code>Schema</code>.</p>
<ol>
<li>Decoupling between processing units<ul>
<li>Schema Driven communication</li>
<li>The <code>Originating Process</code> should remain separate from the <code>Consuming Process</code></li>
</ul>
</li>
<li>Consumer Declared Consumption - <em>this is where we decouple</em><ul>
<li>No concept of <em>registering</em> <strong><em><code>Handlers</code></em></strong></li>
<li><em>Consumers</em> and their associated process <em>may come and go</em></li>
</ul>
</li>
<li>Broadcast &amp; Multicast Origination<ul>
<li>One or Many <em>Originators</em> can produce a message</li>
<li>One or Many <em>Consumers</em> can listen</li>
</ul>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665123223164/2QBBGShDP.png" alt="Blog - Async Mediator - Outbound.png" class="image--center mx-auto" /></p>
<p>Above, we can see the type of outbound Broadcast/Multicast style brokerage we're after. A decoupled, fanout of <em>Messages</em>, is relatively easy to achieve.</p>
<h1 id="heading-putting-it-together">Putting it together</h1>
<h2 id="heading-foundations">Foundations</h2>
<p>Our first step is to split the <em>Originator</em> from <code>Consumer</code> and further avoid any implicit coupling. All <code>Requests</code>, <code>Commands</code>, <code>Notifications</code>, <code>Responses</code>, etc. will travel asynchronously. The building blocks of this system will be the abstract concepts of <strong><em>Schema</em></strong>, <strong><em>Message</em></strong>, and ultimately <strong><em>Flow</em></strong>. </p>
<ul>
<li><strong>Schema</strong> - Defines the shape of data/payload/behavior to be implemented by a <em>Message</em></li>
<li><strong>Message</strong> - Takes the form defined by the <em>Schema</em> and represents an <em>immutable and unique</em> representation of that <em>Schema</em> at a point in time</li>
<li><strong>Flow</strong> -  Is the unidirectional transmission of <em>Messages</em>. A single <em>Flow</em> only permits a single <em>Schema</em></li>
</ul>
<h2 id="heading-async-message-fanout">Async Message Fanout</h2>
<h3 id="heading-abstractions">Abstractions</h3>
<p>Producing a <em>Flow</em> are our two fundamental building blocks: <code>FlowSource</code> &amp; <code>FlowSink</code>. These complimentary components define either end of a <em>Flow</em> constrained to a single <em>Schema</em>. The <em>Messages</em> will be transmitted in the background of our application via a <code>Source</code>/<code>Sink</code> set of abstractions. Each is defined below:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">IFlowSource</span>&lt;<span class="hljs-title">TSchema</span>&gt;
    : <span class="hljs-title">IAsyncDisposable</span>, <span class="hljs-title">IDisposable</span>
    <span class="hljs-keyword">where</span> <span class="hljs-title">TSchema</span> : <span class="hljs-title">Envelope</span>
{
    <span class="hljs-function">ValueTask&lt;<span class="hljs-keyword">bool</span>&gt; <span class="hljs-title">EmitAsync</span>(<span class="hljs-params">TSchema message, CancellationToken cancelToken = <span class="hljs-keyword">default</span></span>)</span>;
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">IFlowSink</span>&lt;<span class="hljs-title">TSchema</span>&gt;
    : <span class="hljs-title">IAsyncDisposable</span>, <span class="hljs-title">IDisposable</span>
    <span class="hljs-keyword">where</span> <span class="hljs-title">TSchema</span> : <span class="hljs-title">Envelope</span>
{
    <span class="hljs-function">IAsyncEnumerable&lt;TSchema&gt; <span class="hljs-title">ConsumeAsync</span>(<span class="hljs-params">CancellationToken cancelToken = <span class="hljs-keyword">default</span></span>)</span>;
}
</code></pre>
<p>Note, both ends of our unidirectional <em>Flow</em> are <code>(Async)Disposable</code>. The unidirectional nature of the <em>Flow</em> leads directly to two implications.</p>
<ol>
<li>Disposing a <code>Sink</code>, disposes only that recipient endpoint</li>
<li>Disposing a <code>Source</code>, however, closes the entirety of the <em>Flow</em></li>
</ol>
<p>Here we've also defined a constraint of Envelope, as seen, this constraint, i.e our base <em>Schema</em>, ensures our <em>Messages</em> always have a <code>CurrentId</code> and a <code>CausationId</code>. All this means is that we know where we are now and where we came from.</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> record <span class="hljs-title">Envelope</span>(<span class="hljs-params">
    <span class="hljs-keyword">string</span> CurrentId,
    <span class="hljs-keyword">string</span> CausationId</span>)</span>;
</code></pre>
<p>Simple <code>Message</code> passing via the twin concepts of Source/Sink allow the <em>Origination</em> and <em>Consumption</em> to be decoupled. Our <code>Source</code>, via an <em>Originator</em>, produces messages at one end and the <code>Sink</code> receives them into a <em>Consumer</em>. This takes advantage of much the same concepts of any <em>Message Bus</em> but applies an asynchronous distributed behavior within a single application.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665123251089/7kLsmOIyH.png" alt="Blog - Async Mediator - Source-Sink.png" class="image--center mx-auto" /></p>
<h3 id="heading-implementations">Implementations</h3>
<p>Our implementations are built upon the now standard <a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/standard/parallel-programming/dataflow-task-parallel-library"><strong><em>System...Dataflow</em></strong></a> namespace containing a wide variety of <em>Dataflow</em> primitives. This library is quite powerful in terms of message passing and parallel processing; complimenting the typical async/await paradigm. Other implementations are of course possible; </p>
<ul>
<li><a target="_blank" href="https://github.com/dotnet/reactive">A little RX - System.Reactive, et. al.</a></li>
<li><a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/core/extensions/channels">Rolling a bit with System.Threading.Channels</a></li>
</ul>
<p>Each has tradeoffs of course, the main driver toward <em>Dataflow</em> was the simplicity of separating <em>Message Passing</em> and <em>Message Consuming</em>. I don't want to force any <em>Consumer</em> into participating in any semantic <em>Observable Pipeline</em>, especially if it is instead better represented as a discrete step. <em>Flow</em> remains opt-in and can be as simple as injection of the <code>Sink</code> and reading from it.
<em>Channels</em> of course could underpin <em>Dataflow</em> but natively <em>Channels</em> are not intended to support any kind of Broadcast/Multicast.</p>
<h3 id="heading-flowsink">FlowSink</h3>
<p>To build our <em>Flow</em> first we'll look at the <code>Sink</code>. The purpose and intention of this component is to be injected via dependency injection into any <code>Consumer</code> that has an interest in the defined <code>Schema</code>. That is;  any defined <em>Consumer</em> that must take action upon receiving a <code>Message</code> with the defined <code>Schema</code>. I've collapsed most of the disposal for brevity; the key piece is disposing of the link back to the <code>Source</code>.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">internal</span> <span class="hljs-keyword">sealed</span> <span class="hljs-keyword">class</span> <span class="hljs-title">FlowSink</span>&lt;<span class="hljs-title">TSchema</span>&gt;
    : <span class="hljs-title">IFlowSink</span>&lt;<span class="hljs-title">TSchema</span>&gt;
    <span class="hljs-keyword">where</span> <span class="hljs-title">TSchema</span> : <span class="hljs-title">Envelope</span>
{
    <span class="hljs-keyword">private</span> BufferBlock&lt;TSchema&gt;? Buffer { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IDisposable link;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">volatile</span> <span class="hljs-keyword">bool</span> isDisposed;


    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">FlowSink</span>(<span class="hljs-params">ILinkableSource&lt;TSchema&gt; source</span>)</span>
    {
        Buffer = <span class="hljs-keyword">new</span>(<span class="hljs-keyword">new</span>()
        {
            EnsureOrdered = <span class="hljs-literal">true</span>,
            BoundedCapacity = DataflowBlockOptions.Unbounded
        });
        link = source.LinkTo(Buffer);
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> IAsyncEnumerable&lt;TSchema&gt; <span class="hljs-title">ConsumeAsync</span>(<span class="hljs-params">CancellationToken cancelToken = <span class="hljs-keyword">default</span></span>)</span> 
        =&gt; Buffer.ThrowIfDisposed(isDisposed)
            .EnumerateSource(cancelToken)
            .Attempt(onError: ex =&gt;
            {
                <span class="hljs-keyword">this</span>.Dispose();
                <span class="hljs-keyword">return</span> AsyncEnumerable.Empty&lt;TSchema&gt;();
            });

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Dispose</span>(<span class="hljs-params"></span>)</span> {<span class="hljs-comment">/*...*/</span>}
    <span class="hljs-function"><span class="hljs-keyword">public</span> ValueTask <span class="hljs-title">DisposeAsync</span>(<span class="hljs-params"></span>)</span> {<span class="hljs-comment">/*...*/</span>}
    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">DisposeCore</span>(<span class="hljs-params"></span>)</span>
    {
        isDisposed = <span class="hljs-literal">true</span>;
        link?.Dispose();
        Buffer = <span class="hljs-literal">null</span>;
        GC.SuppressFinalize(<span class="hljs-keyword">this</span>);
    }
}
</code></pre>
<p>Our <code>FlowSink</code> is built on top of an internal <code>BufferBlock</code> bound to our <code>Schema</code>. We maintain a concrete implementation of <code>BufferBlock</code> with the intention of later using its <code>Count</code> but this could well be represented as a <code>IPropagatorBlock</code> until specificities are necessary. Next, the only item we're dependent on for construction is an <code>ILinkableSource&lt;TItem&gt;</code> defined as follows</p>
<p><em>LinkableSource</em></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">internal</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">ILinkableSource</span>&lt;<span class="hljs-title">TSchema</span>&gt;
    <span class="hljs-keyword">where</span> <span class="hljs-title">TSchema</span> : <span class="hljs-title">Envelope</span>
{
    <span class="hljs-function">IDisposable <span class="hljs-title">LinkTo</span>(<span class="hljs-params">ITargetBlock&lt;TSchema&gt; sink</span>)</span>;
}
</code></pre>
<p>Keeping this interface <code>internal</code> allows us to keep this concept scoped within our package. This narrowly exposes the internal mechanism of <em>Linking</em> two <em>Dataflow Blocks</em> together. Once linked, each block will process messages as defined by its implementation and operate independently of any other within the bounds set by the creation and linking. </p>
<p>Lastly, we can see that the <code>Buffer</code> is consumed via a <em>Disposal</em> and <em>Exception</em> protected cancellable extensions to <code>IAsyncEnumerable</code>. While not necessary for this, we've decorated the <code>CancellationToken</code> as the target of <code>[EnumeratorCancellation]</code> for broader use cases. To keep things brief I'll leave the full implementations for review via GitHub</p>
<pre><code class="lang-csharp">[<span class="hljs-meta">return: NotNull</span>]
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> T <span class="hljs-title">ThrowIfDisposed</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params">
        <span class="hljs-keyword">this</span> T? target,
        <span class="hljs-keyword">bool</span> isDisposed</span>)

<span class="hljs-keyword">internal</span> <span class="hljs-keyword">static</span> <span class="hljs-title">Func</span>&lt;<span class="hljs-title">IAsyncEnumerable</span>&lt;<span class="hljs-title">TSchema</span>&gt;&gt; <span class="hljs-title">EnumerateSource</span>&lt;<span class="hljs-title">TSchema</span>&gt;(<span class="hljs-params">
        <span class="hljs-keyword">this</span> ISourceBlock&lt;TSchema&gt; source,
        CancellationToken cancelToken</span>)

<span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-title">IAsyncEnumerable</span>&lt;<span class="hljs-title">T</span>&gt; <span class="hljs-title">Attempt</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params">
        <span class="hljs-keyword">this</span> Func&lt;IAsyncEnumerable&lt;T&gt;&gt; iterator,
        Func&lt;Exception, IAsyncEnumerable&lt;T&gt;&gt; onError,
        Func&lt;Exception, <span class="hljs-keyword">bool</span>&gt;? canHandle = <span class="hljs-keyword">default</span></span>)
        <span class="hljs-keyword">where</span> T : class</span>
</code></pre>
<p>These are relatively simple extensions, although <code>Attempt</code> has quite the signature 🤯
But each do just what's on the tin; <em>ThrowIfDisposed</em>, <em>EnumerateSource</em>; i.e. Orchestrate the <code>Enumerator</code>, and finally let <em>Attempt</em> manage the execution.</p>
<h3 id="heading-flowsource">FlowSource</h3>
<p>Next is our Broadcast/Multicast enabled <code>Source</code>. This is accomplished by exposing the capabilities of a <code>BroadcastBlock</code>. This block clones, in our case - returns, each message received and <em>Offers</em> it to each <em>Linked</em> block. The importance of <em>Offer</em> is such that if a <em>Linked</em> block cannot take the <code>Message</code>; that <code>Message</code> is then dropped, i.e. lost forever and for good. This leads to <em>Backpressure</em>, another high point for choosing <em>Dataflow</em> yet out of scope here, but we set all <em>Blocks</em> with an <code>UnboundedCapacity</code> for simplicity to begin. So <code>Source</code> can be implemented as such; again with collapsed disposal, we're both <em>Completing</em> and then <em>awaiting Completion</em> of the <code>Source</code> during cleanup.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">internal</span> <span class="hljs-keyword">sealed</span> <span class="hljs-keyword">class</span> <span class="hljs-title">FlowSource</span>&lt;<span class="hljs-title">TSchema</span>&gt;
    : <span class="hljs-title">IFlowSource</span>&lt;<span class="hljs-title">TSchema</span>&gt;,
    <span class="hljs-title">ILinkableSource</span>&lt;<span class="hljs-title">TSchema</span>&gt;
    <span class="hljs-keyword">where</span> <span class="hljs-title">TSchema</span> : <span class="hljs-title">Envelope</span>
{
    <span class="hljs-keyword">private</span> BroadcastBlock&lt;TSchema&gt;? Source { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">volatile</span> <span class="hljs-keyword">bool</span> isDisposed;    

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">FlowSource</span>(<span class="hljs-params"></span>)</span>
        =&gt; Source = <span class="hljs-keyword">new</span>(msg =&gt; msg,
            <span class="hljs-keyword">new</span>()
            {
                EnsureOrdered = <span class="hljs-literal">true</span>,
                BoundedCapacity = DataflowBlockOptions.Unbounded
            });

    <span class="hljs-function"><span class="hljs-keyword">public</span> ValueTask&lt;<span class="hljs-keyword">bool</span>&gt; <span class="hljs-title">EmitAsync</span>(<span class="hljs-params">TSchema message, CancellationToken cancelToken = <span class="hljs-keyword">default</span></span>)</span>
        =&gt; Source.ThrowIfDisposed(isDisposed)
            .OfferAsync(message, TimeSpan.FromMilliseconds(<span class="hljs-number">300</span>), cancelToken)
            .Attempt(onError: ex =&gt; ValueTask.FromResult(<span class="hljs-literal">false</span>));



    IDisposable ILinkableSource&lt;TSchema&gt;.LinkTo(ITargetBlock&lt;TSchema&gt; sink)
        =&gt; Source.ThrowIfDisposed(isDisposed)
            .LinkTo(sink, <span class="hljs-keyword">new</span>()
            {
                PropagateCompletion = <span class="hljs-literal">true</span>,
            });

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Dispose</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-comment">/*...*/</span>}
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> ValueTask <span class="hljs-title">DisposeAsync</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-comment">/*...*/</span>}
    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">async</span> ValueTask <span class="hljs-title">DisposeAsyncCore</span>(<span class="hljs-params"></span>)</span>
    {
        isDisposed = <span class="hljs-literal">true</span>;
        Source?.Complete();
        <span class="hljs-keyword">await</span> (Source?.Completion ?? Task.CompletedTask);
        Source = <span class="hljs-literal">null</span>;
        GC.SuppressFinalize(<span class="hljs-keyword">this</span>);
    }
}
</code></pre>
<p>This implementation exposes <code>EmitAsync</code> and transforms the standard <code>Task&lt;bool&gt;</code> of the <em>Block</em> into a disposed protected and orchestrated <code>Attempt</code> yielding a <code>ValueTask&lt;bool&gt;</code> via simple extensions. Additionally, we separately implement the <code>internal ILinkableSource&lt;TItem&gt;</code> interface to connect any downstream <code>Sinks</code>. This exposes a disposed protected call into <code>.LinkTo</code> ensuring that <em>Completion</em> is propagated. With this configuration set; if the <code>Source</code> is disposed and thus <em>Completed</em> this information will flow down to all <code>Sinks</code> which will then exit any ongoing or new iteration upon the <code>Sink</code>.</p>
<h3 id="heading-registration">Registration</h3>
<p>With just these two components we can achieve the first two Primary Goals, albeit with a little DI trickery</p>
<ol>
<li>Decoupling between processing units</li>
<li>Consumer Declared Consumption</li>
</ol>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> IServiceCollection <span class="hljs-title">AddFlow</span>&lt;<span class="hljs-title">TSchema</span>&gt;(<span class="hljs-params"><span class="hljs-keyword">this</span> IServiceCollection services</span>)
    <span class="hljs-keyword">where</span> TSchema : Envelope</span>
{
    services.TryAddSingleton&lt;IFlowSource&lt;TSchema&gt;, FlowSource&lt;TSchema&gt;&gt;();
    services.TryAddTransient&lt;IFlowSink&lt;TSchema&gt;&gt;(sp =&gt;
    {
        <span class="hljs-keyword">var</span> source = sp.GetRequiredService&lt;IFlowSource&lt;TSchema&gt;&gt;();
        <span class="hljs-keyword">var</span> linkable = source <span class="hljs-keyword">as</span> ILinkableSource&lt;TSchema&gt;
            ?? <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentException(
                <span class="hljs-string">$"Invalid FlowSource Registration. Source Type, <span class="hljs-subst">{source.GetType().Name}</span>, is not linkable"</span>);
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> FlowSink&lt;TSchema&gt;(linkable);
    });
    <span class="hljs-keyword">return</span> services;
}
</code></pre>
<p><strong>Broadcast/Multicast</strong></p>
<p>Registering the <code>FlowSource</code> as a singleton ensures any consumer of this interface is <em><code>Emitting</code></em> to the same <code>BroadcastBlock</code>. This allows one to many <em>Originators</em> to enter <code>Messages</code> into the flow.</p>
<p><strong>Declared Consumption</strong></p>
<p>Thanks to the leniency of the default Dependency Injection of dotnet, i.e. <code>IServiceCollection/IServiceProvider</code>; we can register our <code>Sink</code> as a <em>Transient</em>. Doing so may yield a captured dependency if the consuming service has a longer lifetime than our <code>Sink</code>. However, the advantage is that we ensure each <em>Consumer</em> receives a unique and linked instance of our <code>Sink</code>. In this variation we're leveraging the DI container to dynamically construct our topology. Assuming, 🤞, our <em>Consumers</em> dispose of the <code>Sink</code> properly it will be appropriately removed from the <code>Flow</code> topology.</p>
<h1 id="heading-closure">Closure</h1>
<p>With just these two primary components, <code>FlowSource</code> &amp; <code>FlowSink</code>, we have achieved a basic decoupling and fanout of <code>Messages</code>. We really don't even need a specific <em><code>Mediator</code></em> to do this. </p>
<p>The next evolution is going to be tying things together via the <code>Envelope</code>. This will allow us to put backpressure on a <code>Source</code> while maintaining independence. Additionally, it will provide a vector to ack/nack our <code>Source</code>.</p>
<p>Of course, all the code for this post can be found on GitHub
<a target="_blank" href="https://github.com/ptsteward/ConcurrentFlows.HashNode/tree/master/ConcurrentFlows.AsyncMediator1">ConcurrentFlows.AsyncMediator</a></p>
]]></content:encoded></item><item><title><![CDATA[Domain Model vs. Domain Space]]></title><description><![CDATA[Our Beginning
When we first encounter Domain Modeling we might find ourselves surrounded by examples of people, animals or cars. These concepts are given properties and we start to combine and collect them. We quickly learn the nature of inheritance ...]]></description><link>https://concurrentflows.com/domain-model-vs-domain-space</link><guid isPermaLink="true">https://concurrentflows.com/domain-model-vs-domain-space</guid><category><![CDATA[domain]]></category><category><![CDATA[design patterns]]></category><category><![CDATA[design principles]]></category><dc:creator><![CDATA[Joshua Steward]]></dc:creator><pubDate>Tue, 14 Sep 2021 14:18:39 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1631629102692/JJczluNiB.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="our-beginning">Our Beginning</h1>
<p>When we first encounter <strong>Domain Modeling</strong> we might find ourselves surrounded by examples of people, animals or cars. These concepts are given properties and we start to combine and collect them. We quickly learn the nature of inheritance by learning about specialization of generic concepts; a dog vs. an animal, etc. Then we discuss the behavior of these concepts and have to ask does a Dog: bark, speak or just make noise? So composition is then introduced as an answer to all the noises to be made.  At this point the concept of Object Oriented design is starting to take shape. We learn that in these constraints an <strong>Object,</strong> as it was presented, defines its shape and its behavior. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1631403123839/O_UiesTms.png" alt="2-241.png" /></p>
<p>With that, we may then be thrust into <strong>Domain Driven Design</strong> wherein we learn about the Legos of our Domain Model; the aggregate, entity, value object and so on. Concepts well in hand we construct <strong>Rich Domain Models</strong> ensuring their invariants and described via our ubiquitous language. We stand back with pride at our carefully choreographed model as it expresses our Domain Experts understanding of the <strong>Domain Space</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1631403247910/Qk4hxG187.png" alt="0_28z_AXhf8mXoUihE.png" /></p>
<h1 id="the-test-of-time">The Test of Time</h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1631403067004/M7c39h6ic.jpeg" alt="Kheops-Pyramid.jpg" /></p>
<p>All is well and good until the underpinnings of our <strong>Rich Domain Model</strong> are redefined, shuffled, evolved and put through the meat grinder that is time. Our model was perfect; Time made it wither.</p>
<p>Business demands innovation and the expert knowledge of today is the antiquated ramblings of tomorrow. So how do we model a Domain built on sand? I'd argue the typical <strong>Domain Drive Design</strong> approach is to lay a bedrock of <strong>Domain Expert</strong> driven ubiquitous language, from this bedrock comes the choreography. Confident in our assumptions the <strong>Rich Domain Model</strong> is viewed as malleable to whatever the business demands. But it was the expertise of the <strong>Domain Expert</strong> that shifted. New ideas, optimizations, approaches and evolving definitions all crash though our model tearing down the house of cards. So what then? We build it again? Based off our latest snapshot of a Domain Expert? How can something so malleable become so rigidly orchestrated?</p>
<p>Well maybe we just missed something. </p>
<h1 id="reflecting">Reflecting</h1>
<p>Our <strong>Domain Model</strong> was built as an expression of an instant of time. That is the key failure; we represented the <strong>Domain Space</strong> in a snapshot. Just as a picture is out of date as soon as it's taken, our model is growing stale even as it's implemented. That's is the salient point; <strong><em>our model ignored time</em></strong>.</p>
<p>As engineers we have to recognize that our Domain Experts don't deal in code, they don't get heated about anemic vs. rich models, they don't run their own K8's cluster at home. A <code>Domain Expert</code> squeezes the most defined <code>Success</code> possible out of a given <code>Domain</code>. And every noun in the preceding sentence is subject to evolution. </p>
<p>What we typically resort to is a <strong>Domain Model</strong>, but this is a singular noun describing an instant in time. As engineers our expression medium, code, allows us to transit time effortlessly. Therefore our model has to be evolved to capture the business value we're after. In order to capture the true business value of the <strong>Domain Expert</strong> we need to capture the <strong>Domain Space</strong> and the <strong>Evolutionary Operator</strong> on that <strong>Domain Space</strong>. </p>
<h1 id="redefining">Redefining</h1>
<p>To make progress, as engineers, we stand on our definitions and define our key concepts.</p>
<ul>
<li><strong>Domain Space:</strong> A vector field defined by the degrees of freedom of its constituent nouns and verbs</li>
<li><strong>Evolutionary Operator:</strong> A function that evaluates a point within the Domain Space </li>
<li><strong>Domain Expert:</strong> An Evolutionary Operator on a Domain Space.</li>
<li><strong>Domain Model:</strong> A point within a Domain Space.</li>
</ul>
<p>These were likely not the definitions you had in mind! But through the lens of these definitions we see our <strong>Domain Model</strong> as woefully inadequate to describe what the business is trying to accomplish. Representing a single point within our <strong>Domain Space</strong> is certain to fall victim to the fate we've described above.  </p>
<h1 id="taking-the-plunge">Taking The Plunge</h1>
<h2 id="preamble">Preamble</h2>
<p>You won't see code examples here. Code is the hammer we forge our iron concepts with. Whatever your language, whatever your technique, whatever your paradigm; the concepts are what gets forged into business value.</p>
<h2 id="domain-space">Domain Space</h2>
<p>You might ask, "I've made it this far, now what the hell are you talking about?"</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1631402286150/O0dY3MU17.jpeg" alt="DI_vecfield.jpg" /></p>
<p>A vector field is is the assignment of a vector to every point within a set whose structure is defined by its constituents. These constituents are defined by their degrees of freedom; the axis along which they're allowed to change.</p>
<p>By simply defining the nouns and verbs within our <strong>Domain Space</strong> we start to imply constraints, i.e thing X can change along axis Y. We define nouns in terms of change vectors. Our verbs interact with the nouns and link them in nearly infinite combinations forming networks. Doing this exercise brings our <strong>Domain Space</strong> alive and allows us to see what <strong>Domain Models</strong> can be produced. The possibilities become nearly infinite! Time and all other axes are integrated into one holistic picture.</p>
<h2 id="evolutionary-operator">Evolutionary Operator</h2>
<p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1631401733535/GEX6jhBzY.png" alt="Astro-streamlines.png" />
</p>

<p>We define an <strong>Evolutionary Operator</strong> that works against our defined <strong>Domain Space</strong> with the critical guidance of our <strong>Domain Expert</strong>. Remember that the <strong>Domain Expert</strong> is there to squeeze out success but their expertise is at a point in time. Instead of capturing this expertise in a static <strong>Domain Model</strong>, we dig deeper. We conceptualize the <strong>Domain Expert's</strong> expertise as a function evaluated against our <strong>Domain Space</strong> that yields a <strong>Domain Model</strong>.</p>
<p>Each evolution of the <strong>Domain Expert</strong> yields a different <strong>Evolutionary Operator</strong> and when applied to our <strong>Domain Space</strong> it yields a new <strong>Domain Model</strong>.</p>
<h2 id="what-have-we-gained">What Have We Gained</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1631402744607/eCJJPN_Op.jpeg" alt="10.3934_math.2020134-Figure2.jpg" /></p>
<p>In this exercise we have stressed the importance of defining a <strong>Domain Space</strong>. A broad malleable space that represents the context of your business is key. Remember when defining this, your not capturing the state of the <strong>Domain Experts</strong> view yet, your capturing the real world physical variability and time dependent evolutionary vectors of each noun and verb within your Domain.</p>
<h1 id="finally">Finally</h1>
<p>By modeling a <strong>Domain Space</strong> you create a nearly infinite amount of <strong>Domain Models</strong>. Each point in a <strong>Domain Experts</strong> evolution can yield an executable <strong>Domain Model</strong> derived from the <strong>Domain Space</strong>. </p>
<p>It's this evolutionary robustness the differentiates a <strong>Domain Model</strong> from a <strong>Domain Space</strong>.</p>
<p>Just food for thought we you design your next project.</p>
]]></content:encoded></item><item><title><![CDATA[Decoupled Process Management]]></title><description><![CDATA[Background
Imagine, if you will, that in the course of designing a new api you have the requirement to implement a complex process. The approach presented here will produce a completely message driven architecture that can be implemented and integrat...]]></description><link>https://concurrentflows.com/decoupled-process-management</link><guid isPermaLink="true">https://concurrentflows.com/decoupled-process-management</guid><category><![CDATA[C#]]></category><category><![CDATA[messaging]]></category><category><![CDATA[message queue]]></category><category><![CDATA[dotnet]]></category><category><![CDATA[dotnetcore]]></category><dc:creator><![CDATA[Joshua Steward]]></dc:creator><pubDate>Tue, 06 Jul 2021 14:48:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1625582874467/FlxjMpx7k.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="background">Background</h1>
<p>Imagine, if you will, that in the course of designing a new api you have the requirement to implement a complex process. The approach presented here will produce a completely message driven architecture that can be implemented and integrated with any messaging infrastructure that you choose. This post will cover one way in which you decouple your complex process into a sequence of phases decoupled from the calling code by a messaging system. This system is similar to a pervious post about <a target="_blank" href="https://concurrentflows.hashnode.dev/a-simple-hosted-actor-system">a simple actor system</a>. We're also going to extend the concept presented in that post and marry the concepts with ideas presented in the post <a target="_blank" href="https://concurrentflows.hashnode.dev/message-routing-in-dotnet-6">message routing</a>. </p>
<h1 id="challenge">Challenge</h1>
<p>The challenge here is to derive a generic <code>Process Management System</code>. This system should be capable of driving a user defined process and do so in completely decoupled message driven way.</p>
<h1 id="solution">Solution</h1>
<h2 id="infrastructure">Infrastructure</h2>
<p>First we'll cover the infrastructure of our solution. These components will lay the ground work for our sample.</p>
<h3 id="the-messages">The Messages</h3>
<p>This implementation is going to be completely message driven and independent of the request context. The <code>Process Handlers</code> will live as <code>BackgroundServices</code>and always be alive and ready to process messages. For this system to work first we need to define some base <code>Message</code> records.</p>
<pre><code><span class="hljs-function"><span class="hljs-keyword">public</span> record <span class="hljs-title">ProcessStartMessage</span>&lt;<span class="hljs-title">TInput</span>&gt;(<span class="hljs-params">TInput Input</span>)</span>;

<span class="hljs-function"><span class="hljs-keyword">public</span> record <span class="hljs-title">ProcessStartedMessage</span>(<span class="hljs-params">Guid ProcessId</span>)</span>;

<span class="hljs-function"><span class="hljs-keyword">public</span> record <span class="hljs-title">ProcessEndedMessage</span>(<span class="hljs-params">Guid ProcessId, ProcessPhase Phase</span>)</span>;

<span class="hljs-keyword">public</span> <span class="hljs-keyword">record</span> <span class="hljs-title">ProcessActivity</span>;

<span class="hljs-function"><span class="hljs-keyword">public</span> record <span class="hljs-title">ProcessMessage</span>&lt;<span class="hljs-title">TInput</span>&gt;(<span class="hljs-params">Guid ProcessId, ProcessPhase Phase, TInput Input</span>)</span>;

<span class="hljs-function"><span class="hljs-keyword">public</span> record <span class="hljs-title">ProcessMessage</span>&lt;<span class="hljs-title">TInput</span>, <span class="hljs-title">TActivity</span>&gt;(<span class="hljs-params">Guid ProcessId, ProcessPhase Phase, TInput Input, TActivity Activity</span>)
    : <span class="hljs-title">ProcessMessage</span>&lt;<span class="hljs-title">TInput</span>&gt;(<span class="hljs-params">ProcessId, Phase, Input</span>)
    <span class="hljs-keyword">where</span> TActivity : ProcessActivity
    <span class="hljs-keyword">where</span> TInput : ProcessInput</span>;

<span class="hljs-keyword">public</span> <span class="hljs-keyword">record</span> <span class="hljs-title">ProcessInput</span>;

<span class="hljs-function"><span class="hljs-keyword">public</span> record <span class="hljs-title">ProcessPhase</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> Phase</span>)</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> ProcessPhase Completed = <span class="hljs-keyword">new</span> ProcessPhase(<span class="hljs-keyword">nameof</span>(Completed));
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> ProcessPhase Failed = <span class="hljs-keyword">new</span> ProcessPhase(<span class="hljs-keyword">nameof</span>(Failed));
}
</code></pre><p>Let's go through each message and base type.</p>
<ul>
<li><code>ProcessStartMessage</code>: This message signals the <code>ProcessStartHandler</code> to begin the defined process, this message is used as a type argument constarint and should be the base class of a derived process specific message as we'll see in amoment.</li>
<li><code>ProcessStartedMessage</code>: This is the message that will be published when the process begins and provides the id assigned to the process, so that calling code can use the process id to query information about the state of the process. In this post we'll leave most of the calling code out and focus on the <code>Process Management System</code></li>
<li><code>ProcessEndedMessage</code>: This message signals the calling code that the process has ended, it provides the process id and the phase of the process when the process stopped. This incorporation of the <code>Phase</code> can tell the client whether the process aborted or completed successfully.</li>
<li><code>ProcessMessage&lt;TInput&gt;</code>: This is base of all process messages, this is what we'll use to constrain our <code>PhaseTransitionHandler</code> such that it has access to the properties we need.</li>
<li><code>ProcessMessage&lt;TInput, TActivity&gt;</code>: This message along with an <code>Activity</code> type will be used throughout the process lifetime. The <code>Activity</code> parameter is associated with the <code>ProcessMessage</code> with a particular activity that's being carried out. This message also carries along with it the full input object, the current phase of process and the id of the process to which it's associated. </li>
<li><code>ProcessActivity</code> and <code>ProcessInput</code>: are just constraint records to be derived from for an <code>Activity</code> or <code>Input</code> respectively.</li>
<li><code>ProcessPhase</code>: Process Phase defines the high level general state of the process. For example a derived <code>ProcessPhase</code> could be: <code>Validation</code>, <code>StageRollback</code>, <code>StageInsert</code>. We can derive and define our process in terms of phases. Each phase may generate N messages with N activities. In the base class we define two general <code>Phases</code>: <code>Completed</code> and <code>Failed</code> these two phases are made common to all derived phase sets. I've chose this style of defining phases instead of something like enumeration because personally I don't enums and this record gives us a better constraint since we cannot derive from a base enum.  </li>
</ul>
<p>A process is a set of messages that are initiated by phase transition. A high level view of a process can be seen in this figure</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1625523996219/kE3JE-HDJ.jpeg" alt="Process Handling.jpeg" /></p>
<p>As you can see each phase emits N messages to be collected by the <code>Process Phase Transition Handler</code>. This handler then determines if a phase transition is necessary and if so generates the next phase of messages. If the <code>Process Phase Transition Handler</code> determines the process is <code>Complete</code> a completed message is emitted and the process is over.</p>
<h3 id="the-message-system">The Message System</h3>
<p>Let's now look at the communication stream. This stream abstracts our underlying messaging system into a simple interface with just the methods we need. We could implement this interface with: <code>Channels</code>, <code>Observables</code>, <code>Kafka</code>, <code>Azure Servicebus</code>, <code>SignalR</code>, <code>Azure Pub/Sub</code> or any other messaging system we choose so long as this interface is met.</p>
<pre><code><span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">IMessageSystemReader</span>&lt;<span class="hljs-title">TMessage</span>&gt;
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> ValueTask&lt;<span class="hljs-keyword">bool</span>&gt; <span class="hljs-title">MessageReady</span>(<span class="hljs-params">CancellationToken token = <span class="hljs-keyword">default</span></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">public</span> IAsyncEnumerable&lt;TMessage&gt; <span class="hljs-title">ReadAllAsync</span>(<span class="hljs-params">CancellationToken token = <span class="hljs-keyword">default</span></span>)</span>;
    <span class="hljs-keyword">public</span> Task Completion { <span class="hljs-keyword">get</span>; }
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">IMessageSystemWriter</span>&lt;<span class="hljs-title">TMessage</span>&gt;
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> ValueTask <span class="hljs-title">WriteAsync</span>(<span class="hljs-params">TMessage message, CancellationToken token = <span class="hljs-keyword">default</span></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">public</span> Task <span class="hljs-title">Shutdown</span>(<span class="hljs-params"></span>)</span>;
}
</code></pre><p>Using the <code>Interface Segregation</code> principle we break this interface down into two, one reader and one writer. These interfaces also define a way to shutdown the stream and and notify the client that the stream is now closed. </p>
<p>In this post we'll use channels as our underlying transport.</p>
<pre><code><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">MessageSystem</span>&lt;<span class="hljs-title">TMessage</span>&gt;
    : <span class="hljs-title">IMessageSystemReader</span>&lt;<span class="hljs-title">TMessage</span>&gt;,
    <span class="hljs-title">IMessageSystemWriter</span>&lt;<span class="hljs-title">TMessage</span>&gt;
{
    <span class="hljs-keyword">private</span> ChannelReader&lt;TMessage&gt; reader;
    <span class="hljs-keyword">private</span> ChannelWriter&lt;TMessage&gt; writer;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">MessageSystem</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-keyword">var</span> channel = Channel.CreateUnbounded&lt;TMessage&gt;();
        reader = channel.Reader;
        writer = channel.Writer;
    }

    <span class="hljs-keyword">public</span> Task Completion =&gt; reader.Completion;

    <span class="hljs-function"><span class="hljs-keyword">public</span> ValueTask&lt;<span class="hljs-keyword">bool</span>&gt; <span class="hljs-title">MessageReady</span>(<span class="hljs-params">CancellationToken token = <span class="hljs-keyword">default</span></span>)</span>
        =&gt; reader.WaitToReadAsync(token);

    <span class="hljs-function"><span class="hljs-keyword">public</span> IAsyncEnumerable&lt;TMessage&gt; <span class="hljs-title">ReadAllAsync</span>(<span class="hljs-params">CancellationToken token = <span class="hljs-keyword">default</span></span>)</span>
        =&gt; reader.ReadAllAsync(token);

    <span class="hljs-function"><span class="hljs-keyword">public</span> ValueTask <span class="hljs-title">WriteAsync</span>(<span class="hljs-params">TMessage message, CancellationToken token = <span class="hljs-keyword">default</span></span>)</span>
        =&gt; writer.WriteAsync(message, token);

    <span class="hljs-function"><span class="hljs-keyword">public</span> Task <span class="hljs-title">Shutdown</span>(<span class="hljs-params"></span>)</span>
    {
        writer.Complete();
        <span class="hljs-keyword">return</span> reader.Completion;
    }
}
</code></pre><h3 id="message-system-extensions">Message System Extensions</h3>
<p>As you can see the implementation is just a simple wrapper around a pair of <code>Channel</code> reader/writers.
Next let's add some helper methods to this interface such that all we have to worry about in our <code>Handler</code> code is the logic necessary to handle our defined process.</p>
<pre><code><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title">MessagingExtensions</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">async</span> <span class="hljs-title">IAsyncEnumerable</span>&lt;<span class="hljs-title">TMessage</span>&gt; <span class="hljs-title">ContinuousWaitAndReadAllAsync</span>&lt;<span class="hljs-title">TMessage</span>&gt;(<span class="hljs-params">
        <span class="hljs-keyword">this</span> IMessageSystemReader&lt;TMessage&gt; reader,
        [EnumeratorCancellation] CancellationToken token = <span class="hljs-keyword">default</span></span>)</span>
    {
        <span class="hljs-keyword">while</span> (!reader.Completion.IsCompleted &amp;&amp; !token.IsCancellationRequested)
        {
            <span class="hljs-keyword">var</span> readerReady = <span class="hljs-keyword">await</span> reader.MessageReady(token);
            <span class="hljs-keyword">if</span> (readerReady)
                <span class="hljs-keyword">await</span> <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> message <span class="hljs-keyword">in</span> reader.ReadAllAsync(token))
                    <span class="hljs-keyword">yield</span> <span class="hljs-keyword">return</span> message;
        }
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">async</span> ValueTask <span class="hljs-title">RouteMessageByTypeAsync</span>(<span class="hljs-params"><span class="hljs-keyword">this</span> IWriterProvider provider, <span class="hljs-keyword">object</span> message</span>)</span>
    {
        <span class="hljs-keyword">var</span> writer = provider.RequestWriter(message);
        <span class="hljs-keyword">await</span> writer.WriteAsync((<span class="hljs-keyword">dynamic</span>)message);
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">async</span> ValueTask&lt;<span class="hljs-keyword">bool</span>&gt; <span class="hljs-title">SendIfEnding</span>(<span class="hljs-params"><span class="hljs-keyword">this</span> ProcessPhase phase, IWriterProvider provider, Func&lt;ProcessEndedMessage&gt; endedMessageFatory</span>)</span>
    {
        <span class="hljs-keyword">if</span> (phase == ProcessPhase.Completed || phase == ProcessPhase.Failed)
        {
            <span class="hljs-keyword">await</span> provider.RouteMessageByTypeAsync(endedMessageFatory());
            <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
        }
        <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">bool</span> <span class="hljs-title">ContainsActivity</span>&lt;<span class="hljs-title">TActivity</span>&gt;(<span class="hljs-params"><span class="hljs-keyword">this</span> IEnumerable&lt;<span class="hljs-keyword">dynamic</span>&gt; messages</span>)
        <span class="hljs-keyword">where</span> TActivity : ProcessActivity</span> 
        =&gt; messages.Any(msg =&gt; msg.Activity.GetType() == <span class="hljs-keyword">typeof</span>(TActivity));
}
</code></pre><p>We have one method that wraps the reader waiting and receiving into one easy async enumerator. Then we have the writer method that dispatches a message by it's type. And we have one extension to determine if the process has completed or failed and send out the ended message. And we also have a method to determine what activies exist in the current set of messages. This begs the question; Ok, well what's the <code>WriterProvider</code>? </p>
<h3 id="the-writer-provider">The Writer Provider</h3>
<pre><code><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">WriterProvider</span> : <span class="hljs-title">IWriterProvider</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IServiceProvider serviceProvider;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">WriterProvider</span>(<span class="hljs-params">IServiceProvider serviceProvider</span>)</span>
    {
        <span class="hljs-keyword">this</span>.serviceProvider = serviceProvider ?? <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentNullException(<span class="hljs-keyword">nameof</span>(serviceProvider));
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">dynamic</span> <span class="hljs-title">RequestWriter</span>(<span class="hljs-params"><span class="hljs-keyword">object</span> message</span>)</span>
    {
        <span class="hljs-keyword">var</span> writerType = <span class="hljs-keyword">typeof</span>(IMessageSystemWriter&lt;&gt;).MakeGenericType(message.GetType());
        <span class="hljs-keyword">dynamic</span> writer = serviceProvider.GetService(writerType);
        <span class="hljs-keyword">if</span> (writer <span class="hljs-keyword">is</span> <span class="hljs-literal">null</span>)
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentException(<span class="hljs-string">$"Message Writer not registered for <span class="hljs-subst">{message.GetType().Name}</span>"</span>);
        <span class="hljs-keyword">return</span> writer;
    }
}
</code></pre><p>You may ask, why do we not just use a <code>TMessage</code> type argument instead of <code>message.GetType()</code>, well this is done because <code>TMessage</code> could be a base type and we want the <code>Writer</code> we get to be strongly typed to the actual message that's being sent. Our <code>WriterProvider</code> simply hides the <code>IServiceProvider</code> and uses it to retrieve the correct writer. Remember now that the writer type can be implemented with nearly any transport that can at least satisfy the basic interface. So if we change transports all our code doesn't need to change only the implementation of <code>IMessageSystem&lt;TMessage&gt;</code> needs to change.</p>
<p>Dynamic is chosen for the return type because, remember, we used <code>message.GetType()</code> for the generic type we got from the <code>IServiceProvider</code>. We want to preserve that type and not constrain it to a <code>TMessage</code> which may be a base type.</p>
<h3 id="process-start">Process Start</h3>
<p>Next let's see how we start a process. This is an abstract class that implements the vast majority of functionality any derived handler would need. The responsibilities of this handler are quite simple. It lives as a <code>BackgorundService</code> and listens for a particularly defined <code>TStartMessage</code>. Once a message is received it responds with a defined overridden <code>StartedMessageFactory</code> result. Then it emits the first <code>Phase</code> messages down the line to the next part of the system.</p>
<pre><code><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ProcessStartHandler</span>&lt;<span class="hljs-title">TStartMessage</span>, <span class="hljs-title">TInput</span>&gt;
    : <span class="hljs-title">BackgroundService</span>
    <span class="hljs-keyword">where</span> <span class="hljs-title">TStartMessage</span> : <span class="hljs-title">ProcessStartMessage</span>&lt;<span class="hljs-title">TInput</span>&gt;
    <span class="hljs-keyword">where</span> <span class="hljs-title">TInput</span> : <span class="hljs-title">ProcessInput</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IMessageSystemReader&lt;TStartMessage&gt; startReader;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IWriterProvider writerProvider;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IMessageFactory&lt;TInput&gt; messageFactory;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ProcessPhase startPhase;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">ProcessStartHandler</span>(<span class="hljs-params">
        IWriterProvider writerProvider,
        IMessageFactory&lt;TInput&gt; messageFactory,
        IMessageSystemReader&lt;TStartMessage&gt; startReader,
        ProcessPhase startPhase</span>)</span>
    {
        <span class="hljs-keyword">this</span>.startReader = startReader ?? <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentNullException(<span class="hljs-keyword">nameof</span>(startReader));
        <span class="hljs-keyword">this</span>.writerProvider = writerProvider ?? <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentNullException(<span class="hljs-keyword">nameof</span>(writerProvider));
        <span class="hljs-keyword">this</span>.messageFactory = messageFactory ?? <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentNullException(<span class="hljs-keyword">nameof</span>(messageFactory));
        <span class="hljs-keyword">this</span>.startPhase = startPhase ?? <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentNullException(<span class="hljs-keyword">nameof</span>(startPhase));
    }

    <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">ExecuteAsync</span>(<span class="hljs-params">CancellationToken stoppingToken</span>)</span>
    {
        <span class="hljs-keyword">await</span> <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> message <span class="hljs-keyword">in</span> startReader.ContinuousWaitAndReadAllAsync(stoppingToken))
        {
            <span class="hljs-keyword">var</span> processId = Guid.NewGuid();
            <span class="hljs-keyword">await</span> SendStartedMessage(processId);
            <span class="hljs-keyword">await</span> SendFirstPhaseMessages(processId, message);
        }
    }

    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">async</span> ValueTask <span class="hljs-title">SendStartedMessage</span>(<span class="hljs-params">Guid processId</span>)</span>
    {

        <span class="hljs-keyword">var</span> message = StartedMessageFactory(processId);
        <span class="hljs-keyword">await</span> writerProvider.RouteMessageByTypeAsync(message);
    }

    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">async</span> ValueTask <span class="hljs-title">SendFirstPhaseMessages</span>(<span class="hljs-params">Guid processId, TStartMessage message</span>)</span>
    {
        <span class="hljs-keyword">await</span> <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> newMessage <span class="hljs-keyword">in</span> messageFactory[startPhase](processId, startPhase, message.Input, Enumerable.Empty&lt;<span class="hljs-keyword">object</span>&gt;()))
        {
            <span class="hljs-keyword">await</span> writerProvider.RouteMessageByTypeAsync(newMessage);
        }

    }

    <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">abstract</span> ProcessStartedMessage <span class="hljs-title">StartedMessageFactory</span>(<span class="hljs-params">Guid processId</span>)</span>;
}
</code></pre><p>With our handy extension methods in use for both reading and writing our code in here is straight to the point: Listen for start, Emit started with <code>ProcessId</code> &amp; Emit first phase messages. Now you may be asking; What's the message factory and why is it needed?
Well we don't want our handlers to have too much responsibility. The start handler already covers a lot of functionality and it shouldn't be responsible for knowing how to format/create/generate the first phase messages. If it were to be responsible for that we could end up with a huge list of dependencies and even new type parameters to deal with. This would be unsatisfactory, so we delegate to a single purpose object: the message factory.</p>
<h3 id="the-message-factory">The Message Factory</h3>
<pre><code><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IMessageFactory</span>&lt;<span class="hljs-type">TInput</span>&gt; </span>
    : IReadOnlyDictionary&lt;ProcessPhase, Func&lt;ProcessPhase, ProcessInput, IEnumerable&lt;<span class="hljs-keyword">object</span>&gt;, IAsyncEnumerable&lt;<span class="hljs-keyword">object</span>&gt;&gt;&gt;
    <span class="hljs-keyword">where</span> TInput : ProcessInput
{

}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MessageFactory</span>&lt;<span class="hljs-type">TInput</span>&gt;</span>
    : Dictionary&lt;ProcessPhase, Func&lt;Guid, ProcessPhase, TInput, IEnumerable&lt;<span class="hljs-keyword">object</span>&gt;, IAsyncEnumerable&lt;<span class="hljs-keyword">object</span>&gt;&gt;&gt;,
    IProcessMessageFactory&lt;TInput&gt;
    <span class="hljs-keyword">where</span> TInput : ProcessInput
{

}
</code></pre><p>As you can see this is a generic interface that simply needs the type of <code>TInput</code> and the rest is quite simple. Based on a <code>ProcessPhase</code> key we get a <code>Func</code> that takes the current phase, the <code>ProcessInput</code> and a collection that is describing the currently received messages for this process. With these inputs it generates a batch of messages to be sent out. When this interface is implemented each phase of the implementing process must be accounted for.</p>
<p>We also have a handy abstract class for implementations to inherit from such that all they are concerned with is defining what messages come from specific keys.</p>
<h3 id="phase-transitioning">Phase Transitioning</h3>
<p>Next, we're going to look at the next abstract <code>BackgroundService</code>, this is the only other operating service in this system. This Handler listens for any of the predefined <code>TMessage</code>, collects them and uses both the <code>MessageFactory</code> we've seen and the upcoming <code>PhaseTransitions</code> factory.</p>
<pre><code><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">class</span> <span class="hljs-title">PhaseTransitionHandler</span>&lt;<span class="hljs-title">TMessage</span>, <span class="hljs-title">TInput</span>&gt;
    : <span class="hljs-title">BackgroundService</span>
    <span class="hljs-keyword">where</span> <span class="hljs-title">TMessage</span> : <span class="hljs-title">ProcessMessage</span>&lt;<span class="hljs-title">TInput</span>&gt;
    <span class="hljs-keyword">where</span> <span class="hljs-title">TInput</span> : <span class="hljs-title">ProcessInput</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IWriterProvider writerProvider;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IPhaseTransitions&lt;TInput&gt; phaseTransitions;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IMessageFactory&lt;TInput&gt; messageFactory;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IMessageSystemReader&lt;TMessage&gt; reader;

    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-title">ConcurrentDictionary</span>&lt;<span class="hljs-title">Guid</span>, <span class="hljs-title">ICollection</span>&lt;<span class="hljs-title">object</span>&gt;&gt; MessagesReceived</span> = <span class="hljs-keyword">new</span> ConcurrentDictionary&lt;Guid, ICollection&lt;<span class="hljs-keyword">object</span>&gt;&gt;();

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">PhaseTransitionHandler</span>(<span class="hljs-params">
        IWriterProvider writerProvider,
        IPhaseTransitions&lt;TInput&gt; phaseTransitions,
        IMessageFactory&lt;TInput&gt; messageFactory,
        IMessageSystemReader&lt;TMessage&gt; reader</span>)</span>
    {
        <span class="hljs-keyword">this</span>.writerProvider = writerProvider ?? <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentNullException(<span class="hljs-keyword">nameof</span>(writerProvider));
        <span class="hljs-keyword">this</span>.phaseTransitions = phaseTransitions ?? <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentNullException(<span class="hljs-keyword">nameof</span>(phaseTransitions));
        <span class="hljs-keyword">this</span>.messageFactory = messageFactory ?? <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentNullException(<span class="hljs-keyword">nameof</span>(messageFactory));
        <span class="hljs-keyword">this</span>.reader = reader ?? <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentNullException(<span class="hljs-keyword">nameof</span>(reader));
    }

    <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">ExecuteAsync</span>(<span class="hljs-params">CancellationToken stoppingToken</span>)</span>
    {
        <span class="hljs-keyword">await</span> <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> message <span class="hljs-keyword">in</span> reader.ContinuousWaitAndReadAllAsync(stoppingToken))
        {
            <span class="hljs-keyword">if</span> (MessagesReceived.TryGetValue(message.ProcessId, <span class="hljs-keyword">out</span> <span class="hljs-keyword">var</span> messages))
                messages.Add(message);
            <span class="hljs-keyword">else</span>
                MessagesReceived[message.ProcessId] = <span class="hljs-keyword">new</span> List&lt;<span class="hljs-keyword">object</span>&gt;() { message };

            <span class="hljs-keyword">var</span> nextPhase = phaseTransitions[message.Phase](message.Phase, message.Input, MessagesReceived[message.ProcessId]);
            <span class="hljs-keyword">if</span> (<span class="hljs-keyword">await</span> nextPhase.SendIfEnding(writerProvider, () =&gt; EndedMessageFactory(message.ProcessId, nextPhase)))
            {
                MessagesReceived.Remove(message.ProcessId, <span class="hljs-keyword">out</span> <span class="hljs-keyword">var</span> _);
                <span class="hljs-keyword">await</span> CompletedEvent(nextPhase, message);
            }
            <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (ShouldTransition(message.Phase, nextPhase))
            {
                <span class="hljs-keyword">await</span> PhaseTransitionEvent(nextPhase, message);
                <span class="hljs-keyword">await</span> <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> newMessage <span class="hljs-keyword">in</span> messageFactory[nextPhase](message.ProcessId, nextPhase, message.Input, MessagesReceived[message.ProcessId]))
                {
                    <span class="hljs-keyword">await</span> writerProvider.RouteMessageByTypeAsync(newMessage);
                }
            }
        }
    }

    <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">abstract</span> ProcessEndedMessage <span class="hljs-title">EndedMessageFactory</span>(<span class="hljs-params">Guid processId, ProcessPhase phase</span>)</span>;

    <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">virtual</span> ValueTask <span class="hljs-title">CompletedEvent</span>(<span class="hljs-params">ProcessPhase phase, TMessage message</span>)</span>
        =&gt; ValueTask.CompletedTask;

    <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">virtual</span> ValueTask <span class="hljs-title">PhaseTransitionEvent</span>(<span class="hljs-params">ProcessPhase phase, TMessage message</span>)</span> 
        =&gt; ValueTask.CompletedTask;

    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">bool</span> <span class="hljs-title">ShouldTransition</span>(<span class="hljs-params">ProcessPhase currentPhase, ProcessPhase newPhase</span>)</span>
        =&gt; !currentPhase.Equals(newPhase);
}
</code></pre><p>This handler listens for any of defined <code>TMessage</code> types and collects them by <code>ProcessId</code>. Each time a message is received and stored the <code>PhaseTranstions</code> component is used to check whether or not to transition to a new phase. If a Phase transition is required the handler then uses the <code>MessageFactory</code> to produce and then send the next batch of messages. This handler also provides hooks into the process for both the <code>CompletedEvent</code> and the <code>PhaseTransitionEvent</code> such that inheriters can perform any extra logic they might want on those two events.</p>
<h3 id="the-phase-transition-dictionary">The Phase Transition Dictionary</h3>
<p>Similar to the <code>MessageFactory</code> our <code>PhaseTransition</code> dictionary is keyed by <code>ProcessPhase</code> and produces a function that takes: the current phase, the original input, a collection of returned message and produces a <code>ProcessPhase</code> if the phase produced is different from the current phase, the <code>PhaseTransitionHandler</code> responds appropriately by moving on to the next batch of messages.</p>
<pre><code><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IPhaseTransitions</span>&lt;<span class="hljs-type">TInput</span>&gt;</span>
    : IReadOnlyDictionary&lt;ProcessPhase, Func&lt;ProcessPhase, TInput, IEnumerable&lt;<span class="hljs-keyword">object</span>&gt;, ProcessPhase&gt;&gt;
    <span class="hljs-keyword">where</span> TInput : ProcessInput
{

}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PhaseTransitions</span>&lt;<span class="hljs-type">TInput</span>&gt;</span>
    : Dictionary&lt;ProcessPhase, Func&lt;ProcessPhase, TInput, IEnumerable&lt;<span class="hljs-keyword">object</span>&gt;, ProcessPhase&gt;&gt;,
    IPhaseTransitions&lt;TInput&gt;
    <span class="hljs-keyword">where</span> TInput : ProcessInput
{

}
</code></pre><p>Again we have a handy abstract base class that inherits a <code>Dictionary</code> so all the implementation has to do is fill itself with the correct Phase Transitions.</p>
<h3 id="the-worker">The Worker</h3>
<p>So now we have a whole system intended to produce messages based on the phase of a process. But we still need something to process those messages and do the actual work those messages entail. Enter the <code>Command Handler</code>, we could call this an Actor but to fit the terminology used here we'll just refer to it as a Handler. I already posted about <a target="_blank" href="https://concurrentflows.hashnode.dev/a-simple-hosted-actor-system">Query Actors</a> which take a query and then return a response. Since our process is completely async we won't be using the request/response architecture described in that post. Instead our command handler will process the incoming message or command and send out a response.</p>
<pre><code><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">class</span> <span class="hljs-title">CommandHandler</span>&lt;<span class="hljs-title">TMesssage</span>&gt; : <span class="hljs-title">BackgroundService</span>
{
    <span class="hljs-keyword">protected</span> <span class="hljs-keyword">readonly</span> IMessageSystemReader&lt;TMesssage&gt; reader;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">CommandHandler</span>(<span class="hljs-params">IMessageSystemReader&lt;TMesssage&gt; reader</span>)</span>
    {
        <span class="hljs-keyword">this</span>.reader = reader ?? <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentNullException(<span class="hljs-keyword">nameof</span>(reader));
    }

    <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">ExecuteAsync</span>(<span class="hljs-params">CancellationToken stoppingToken</span>)</span>
    {
        <span class="hljs-keyword">await</span> <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> command <span class="hljs-keyword">in</span> reader.ContinuousWaitAndReadAllAsync(stoppingToken))
        {
            <span class="hljs-keyword">await</span> HandleAsync(command, stoppingToken);
        }
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> ValueTask <span class="hljs-title">HandleAsync</span>(<span class="hljs-params">TMesssage command, CancellationToken stoppingToken</span>)</span>;
}
</code></pre><h3 id="the-registrations">The Registrations</h3>
<p>Finally we need to register all the components with our DI. This is done through a set of extension methods</p>
<pre><code><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title">RegistrationExtensions</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> IServiceCollection <span class="hljs-title">AddMessageSystem</span>&lt;<span class="hljs-title">TMessage</span>&gt;(<span class="hljs-params"><span class="hljs-keyword">this</span> IServiceCollection services</span>)</span>
    {
        <span class="hljs-keyword">var</span> messageSystem = <span class="hljs-keyword">new</span> MessageSystem&lt;TMessage&gt;();
        services.AddSingleton&lt;IMessageSystemWriter&lt;TMessage&gt;&gt;(messageSystem);
        services.AddSingleton&lt;IMessageSystemReader&lt;TMessage&gt;&gt;(messageSystem);
        <span class="hljs-keyword">return</span> services;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> IServiceCollection <span class="hljs-title">AddCommandHandler</span>&lt;<span class="hljs-title">TActor</span>, <span class="hljs-title">TCommand</span>&gt;(<span class="hljs-params"><span class="hljs-keyword">this</span> IServiceCollection services</span>)
        <span class="hljs-keyword">where</span> TActor : CommandHandler&lt;TCommand&gt;</span> 
        =&gt; services
            .AddHostedService&lt;TActor&gt;()
            .AddMessageSystem&lt;TCommand&gt;();

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> IServiceCollection <span class="hljs-title">AddWriterProvider</span>(<span class="hljs-params"><span class="hljs-keyword">this</span> IServiceCollection services</span>)</span>
        =&gt; services.AddSingleton&lt;IWriterProvider, WriterProvider&gt;();

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> IServiceCollection <span class="hljs-title">AddProcessStartHandler</span>&lt;<span class="hljs-title">THandler</span>, <span class="hljs-title">TMessageFactory</span>, <span class="hljs-title">TStartMessage</span>, <span class="hljs-title">TEndMessage</span>, <span class="hljs-title">TInput</span>&gt;(<span class="hljs-params"><span class="hljs-keyword">this</span> IServiceCollection services</span>)
        <span class="hljs-keyword">where</span> THandler : ProcessStartHandler&lt;TStartMessage, TInput&gt;
        <span class="hljs-keyword">where</span> TMessageFactory : MessageFactory&lt;TInput&gt;
        <span class="hljs-keyword">where</span> TStartMessage : ProcessStartMessage&lt;TInput&gt;
        <span class="hljs-keyword">where</span> TInput : ProcessInput</span>
        =&gt; services
            .AddHostedService&lt;THandler&gt;()
            .AddSingleton&lt;IMessageFactory&lt;TInput&gt;, TMessageFactory&gt;()
            .AddMessageSystem&lt;TStartMessage&gt;()
            .AddMessageSystem&lt;TEndMessage&gt;();

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> IServiceCollection <span class="hljs-title">AddPhaseTransitionHandler</span>&lt;<span class="hljs-title">THandler</span>, <span class="hljs-title">TPhaseTransitions</span>, <span class="hljs-title">TMessage</span>, <span class="hljs-title">TInput</span>&gt;(<span class="hljs-params"><span class="hljs-keyword">this</span> IServiceCollection services</span>)
        <span class="hljs-keyword">where</span> THandler : PhaseTransitionHandler&lt;TMessage, TInput&gt;
        <span class="hljs-keyword">where</span> TPhaseTransitions : PhaseTransitions&lt;TInput&gt;
        <span class="hljs-keyword">where</span> TMessage : ProcessMessage&lt;TInput&gt;
        <span class="hljs-keyword">where</span> TInput : ProcessInput</span> 
        =&gt; services
            .AddHostedService&lt;THandler&gt;()
            .AddSingleton&lt;IPhaseTransitions&lt;TInput&gt;, TPhaseTransitions&gt;()
            .AddMessageSystem&lt;TMessage&gt;();
}
</code></pre><p>These extension methods are all we need to register our entire <code>Process Management System</code>. 
The first registers the implementation of our <code>Message System</code> based on a defined message type parameter.
The next, registers our <code>Command Handler</code> and it's associated <code>Message System</code>
The next just registers our <code>Writer Provider</code>.
Then we register the <code>Process Start Handler</code> along with the <code>Message Factory</code> and the appropriate input and output channels. 
And, finally we register the <code>Phase Transition Handler</code>, the <code>Phase Transitions Dictionary</code> and it's input channels.</p>
<h2 id="sample-demo">Sample Demo</h2>
<h3 id="overview">Overview</h3>
<p>Now that we have all the infrastructure in place it's time to make use of it. For this example we'll be doing a basic "Hello World" type process. We'll define all our messages, phases, and handlers. The goal is to have process that has two steps: Validate the input, Respond with a message.</p>
<h3 id="the-messages">The Messages</h3>
<p>The messages for our sample define the ways in which downstream consumers will respond and how we expect them to act. We define our process as a series of messages.
This sample process will first validate our input with some simple validation, then it will write out the message to consumers. This process extends the <code>ProcessPhase</code> by defining two additional phases of our process <code>Validation</code> and <code>SayHello</code>.</p>
<pre><code><span class="hljs-function"><span class="hljs-keyword">public</span> record <span class="hljs-title">SayHelloInput</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> Name</span>)
    : ProcessInput</span>;

<span class="hljs-function"><span class="hljs-keyword">public</span> record <span class="hljs-title">SayHelloProcessStartMessage</span>(<span class="hljs-params">SayHelloInput Input</span>)
    : <span class="hljs-title">ProcessStartMessage</span>&lt;<span class="hljs-title">SayHelloInput</span>&gt;(<span class="hljs-params">Input</span>)</span>;

<span class="hljs-function"><span class="hljs-keyword">public</span> record <span class="hljs-title">SayHelloProcessStartedMessage</span>(<span class="hljs-params">Guid ProcessId</span>)
    : <span class="hljs-title">ProcessStartedMessage</span>(<span class="hljs-params">ProcessId</span>)</span>;

<span class="hljs-function"><span class="hljs-keyword">public</span> record <span class="hljs-title">SayHelloEndedMessage</span>(<span class="hljs-params">Guid ProcessId, ProcessPhase Phase</span>)
        : <span class="hljs-title">ProcessEndedMessage</span>(<span class="hljs-params">ProcessId, Phase</span>)</span>;

<span class="hljs-function"><span class="hljs-keyword">public</span> record <span class="hljs-title">SayHelloProcessMessage</span>&lt;<span class="hljs-title">TActivity</span>&gt;(<span class="hljs-params">Guid ProcessId, ProcessPhase Phase, SayHelloInput Input, TActivity Activity</span>)
    : <span class="hljs-title">ProcessMessage</span>&lt;<span class="hljs-title">SayHelloInput</span>, <span class="hljs-title">TActivity</span>&gt;(<span class="hljs-params">ProcessId, Phase, Input, Activity</span>)
    <span class="hljs-keyword">where</span> TActivity : ProcessActivity</span>;

<span class="hljs-function"><span class="hljs-keyword">public</span> record <span class="hljs-title">SayHelloValidation</span>(<span class="hljs-params">SayHelloInput Input</span>)
        : ProcessActivity</span>;

<span class="hljs-keyword">public</span> <span class="hljs-keyword">record</span> <span class="hljs-title">SayHelloValidationSuccess</span>
    : <span class="hljs-title">ProcessActivity</span>;

<span class="hljs-keyword">public</span> <span class="hljs-keyword">record</span> <span class="hljs-title">SayHelloValidationFailure</span>
    : <span class="hljs-title">ProcessActivity</span>;

<span class="hljs-function"><span class="hljs-keyword">public</span> record <span class="hljs-title">SayHelloResponseActivity</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> Input</span>)
    : ProcessActivity</span>;

<span class="hljs-keyword">public</span> <span class="hljs-keyword">record</span> <span class="hljs-title">SayHelloCompletedActivity</span>
    : <span class="hljs-title">ProcessActivity</span>;

<span class="hljs-function"><span class="hljs-keyword">public</span> record <span class="hljs-title">SayHelloResponseMessage</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> message</span>)</span>;

<span class="hljs-function"><span class="hljs-keyword">public</span> record <span class="hljs-title">SayHelloPhases</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> Phase</span>)
        : <span class="hljs-title">ProcessPhase</span>(<span class="hljs-params">Phase</span>)</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> ProcessPhase Validation = <span class="hljs-keyword">new</span> ProcessPhase(<span class="hljs-keyword">nameof</span>(Validation));
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> ProcessPhase SayHello = <span class="hljs-keyword">new</span> ProcessPhase(<span class="hljs-keyword">nameof</span>(SayHello));
}
</code></pre><p>These messages, activities and inputs define our <code>Say Hello</code> process. We start with the start message that carries the user input into our process stream. We have a derived started message to signal the client that the process has started and a derived ended message to signal that the process has ended in a particular phase. Next we have a derived process message that will be used to carry out our process doing specified activities. We have defined four activities for this process <code>SayHelloValidation</code> <code>SayHelloValidationSuccess</code>, <code>SayHelloValidationFailure</code> and <code>SayHelloRepsonse</code>. These activities will be coordinated by our <code>PhaseTransition</code> handler and our eventual message factory we'll see in a moment. And finally we defined the phases of our process as <code>Validation</code> and <code>SayHello</code>, remember our base record <code>ProcessPhase</code> already defines <code>Completed</code> and <code>Failed</code> for us so all we need to do is define the working phases of our process.</p>
<h3 id="the-process-handlers">The Process Handlers</h3>
<p>Next we define our derived handlers for our specific process, first the <code>Start Handler</code></p>
<pre><code><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">SayHelloStartHandler</span> : <span class="hljs-title">ProcessStartHandler</span>&lt;<span class="hljs-title">SayHelloProcessStartMessage</span>, <span class="hljs-title">SayHelloInput</span>&gt;
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">SayHelloStartHandler</span>(<span class="hljs-params">
        IWriterProvider writerProvider,
        IMessageFactory&lt;SayHelloInput&gt; messageFactory,
        IMessageSystemReader&lt;SayHelloProcessStartMessage&gt; startReader</span>)
        : <span class="hljs-title">base</span>(<span class="hljs-params">writerProvider, messageFactory, startReader, SayHelloPhases.Validation</span>)</span>
    {
    }

    <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">override</span> ProcessStartedMessage <span class="hljs-title">StartedMessageFactory</span>(<span class="hljs-params">Guid processId</span>)</span>
        =&gt; <span class="hljs-keyword">new</span> SayHelloProcessStartedMessage(processId);
}
</code></pre><p>Since we don't need any additional functionality, all we do is specify the working types and implement the message factory and constructor and we're done with this!
Then for our concreate <code>Message Factory</code></p>
<pre><code><span class="hljs-built_in">public</span> <span class="hljs-keyword">class</span> SayHelloMessageFactory : MessageFactory&lt;SayHelloInput&gt;
{
    <span class="hljs-built_in">public</span> SayHelloMessageFactory()
    {
        this[SayHelloPhases.Validation] = (processId, phase, <span class="hljs-keyword">input</span>, messages) =&gt; ValidationPhaseMessages(processId, phase, <span class="hljs-keyword">input</span>, messages);
        this[SayHelloPhases.SayHello] = (processId, phase, <span class="hljs-keyword">input</span>, messages) =&gt; SayHelloPhaseMessages(processId, phase, <span class="hljs-keyword">input</span>, messages);
    }

    <span class="hljs-built_in">public</span> IAsyncEnumerable&lt;<span class="hljs-keyword">object</span>&gt; ValidationPhaseMessages(Guid processId, ProcessPhase phase, SayHelloInput <span class="hljs-keyword">input</span>, IEnumerable&lt;dynamic&gt; currentMessages)
        =&gt; <span class="hljs-built_in">new</span>[]
        {
            <span class="hljs-built_in">new</span> SayHelloProcessMessage&lt;SayHelloValidation&gt;(processId, phase, <span class="hljs-keyword">input</span>, <span class="hljs-built_in">new</span> SayHelloValidation(<span class="hljs-keyword">input</span>))
        }.ToAsyncEnumerable();

    <span class="hljs-built_in">public</span> IAsyncEnumerable&lt;<span class="hljs-keyword">object</span>&gt; SayHelloPhaseMessages(Guid processId, ProcessPhase phase, SayHelloInput <span class="hljs-keyword">input</span>, IEnumerable&lt;dynamic&gt; currentMessages)
        =&gt; <span class="hljs-built_in">new</span>[]
        {
            <span class="hljs-built_in">new</span> SayHelloProcessMessage&lt;SayHelloResponseActivity&gt;(processId, phase, <span class="hljs-keyword">input</span>, <span class="hljs-built_in">new</span> SayHelloResponseActivity(<span class="hljs-keyword">input</span>.Name))
        }.ToAsyncEnumerable();
}
</code></pre><p>Since we only have two phases and each phase only produces one message our <code>Message Factory</code> is quite simple in this case.
Next we define our <code>Phase Transition Handler</code></p>
<pre><code><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SayHelloPhaseTransistionsHandler</span> :</span> PhaseTransitionHandler&lt;SayHelloProcessMessage&lt;ProcessActivity&gt;, SayHelloInput&gt;
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">SayHelloPhaseTransistionsHandler</span><span class="hljs-params">(
        IWriterProvider writerProvider,
        IPhaseTransitions&lt;SayHelloInput&gt; phaseTransitions,
        IMessageFactory&lt;SayHelloInput&gt; messageFactory,
        IMessageSystemReader&lt;SayHelloProcessMessage&lt;ProcessActivity&gt;&gt; reader)</span>
        : <span class="hljs-title">base</span><span class="hljs-params">(writerProvider, phaseTransitions, messageFactory, reader)</span>
    </span>{
    }

    <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">override</span> ProcessEndedMessage <span class="hljs-title">EndedMessageFactory</span><span class="hljs-params">(Guid processId, ProcessPhase phase)</span>
        </span>=&gt; <span class="hljs-keyword">new</span> SayHelloEndedMessage(processId, phase);
}
</code></pre><p>And again no special behavior is needed so all we're doing is setting type arguments, and implementing the constructor and ended message factory.
Finally, our <code>Phase Transitions</code> gets defined.</p>
<pre><code><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SayHelloPhaseTransitions</span> : <span class="hljs-type">PhaseTransitions</span>&lt;<span class="hljs-type">SayHelloInput</span>&gt;</span>
{
    <span class="hljs-keyword">public</span> SayHelloPhaseTransitions()
    {
        <span class="hljs-keyword">this</span>[SayHelloPhases.Validation] = (phase, input, messages) =&gt; ValidationPhaseTransition(phase, input, messages);
        <span class="hljs-keyword">this</span>[SayHelloPhases.SayHello] = (phase, input, messages) =&gt; SayHelloPhaseTransition(phase, input, messages);
    }

    <span class="hljs-keyword">public</span> ProcessPhase ValidationPhaseTransition(ProcessPhase phase, SayHelloInput input, IEnumerable&lt;<span class="hljs-keyword">dynamic</span>&gt; currentMessages)
    {
        <span class="hljs-keyword">if</span> (currentMessages.ContainsActivity&lt;SayHelloValidationSuccess&gt;())
            <span class="hljs-keyword">return</span> SayHelloPhases.SayHello;
        <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (currentMessages.ContainsActivity&lt;SayHelloValidationFailure&gt;())
            <span class="hljs-keyword">return</span> SayHelloPhases.Failed;
        <span class="hljs-keyword">return</span> phase;
    }

    <span class="hljs-keyword">public</span> ProcessPhase SayHelloPhaseTransition(ProcessPhase phase, SayHelloInput input, IEnumerable&lt;<span class="hljs-keyword">dynamic</span>&gt; currentMessages)
    {
        <span class="hljs-keyword">if</span> (currentMessages.ContainsActivity&lt;SayHelloCompletedActivity&gt;())
            <span class="hljs-keyword">return</span> SayHelloPhases.Completed;
        <span class="hljs-keyword">return</span> phase;
    }
}
</code></pre><p>Note how we use the state provided to compute the next phase of the process, if validation fails we move directly to failed, if validation succeeds we continue on to the next phase. Once the <code>SayHelloCompletedActivity</code> has been emitted we mark the process as <code>Completed</code>.</p>
<h3 id="the-workers">The Workers</h3>
<p>First we implement our validation handler. The validation we're doing here is to simply check that the string is not too long.</p>
<pre><code><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> SayHelloValidationHandler
    : CommandHandler&lt;SayHelloProcessMessage&lt;SayHelloValidation&gt;&gt;
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IMessageSystemWriter&lt;SayHelloProcessMessage&lt;ProcessActivity&gt;&gt; successWriter;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IMessageSystemWriter&lt;SayHelloProcessMessage&lt;ProcessActivity&gt;&gt; failureWriter;

    <span class="hljs-keyword">public</span> SayHelloValidationHandler(
        IMessageSystemReader&lt;SayHelloProcessMessage&lt;SayHelloValidation&gt;&gt; reader,
        IMessageSystemWriter&lt;SayHelloProcessMessage&lt;ProcessActivity&gt;&gt; successWriter,
        IMessageSystemWriter&lt;SayHelloProcessMessage&lt;ProcessActivity&gt;&gt; failureWriter)
        : base(reader)
    {
        <span class="hljs-built_in">this</span>.successWriter = successWriter ?? <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentNullException(nameof(successWriter));
        <span class="hljs-built_in">this</span>.failureWriter = failureWriter ?? <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentNullException(nameof(failureWriter));
    }

    <span class="hljs-keyword">public</span> override <span class="hljs-keyword">async</span> ValueTask HandleAsync(SayHelloProcessMessage&lt;SayHelloValidation&gt; command, CancellationToken stoppingToken)
    {
        <span class="hljs-keyword">var</span> input = command.Input.Name;
        <span class="hljs-keyword">if</span> (input.Length &gt; <span class="hljs-number">10</span>)
            <span class="hljs-keyword">await</span> failureWriter.WriteAsync(
                <span class="hljs-keyword">new</span> SayHelloProcessMessage&lt;ProcessActivity&gt;(command.ProcessId, command.Phase, command.Input, <span class="hljs-keyword">new</span> SayHelloValidationFailure()));
        <span class="hljs-keyword">else</span>
            <span class="hljs-keyword">await</span> successWriter.WriteAsync(
                <span class="hljs-keyword">new</span> SayHelloProcessMessage&lt;ProcessActivity&gt;(command.ProcessId, command.Phase, command.Input, <span class="hljs-keyword">new</span> SayHelloValidationSuccess()));
    }
}
</code></pre><p>Notice how we only need to implement the <code>HandleAsync</code> method and are provided with read command from our <code>Message System</code>. If validation passes we emit a successful activity, if validation fails we emit a failed activity and the <code>Phase Transition Dictionary</code> and <code>Handler</code> will take it from there.
Next we define our <code>Say Hello Handler</code></p>
<pre><code><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> SayHelloResponseHandler
    : CommandHandler&lt;SayHelloProcessMessage&lt;SayHelloResponseActivity&gt;&gt;
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IMessageSystemWriter&lt;SayHelloResponseMessage&gt; responseWriter;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IMessageSystemWriter&lt;SayHelloProcessMessage&lt;ProcessActivity&gt;&gt; completedWriter;

    <span class="hljs-keyword">public</span> SayHelloResponseHandler(
        IMessageSystemReader&lt;SayHelloProcessMessage&lt;SayHelloResponseActivity&gt;&gt; reader,
        IMessageSystemWriter&lt;SayHelloResponseMessage&gt; responseWriter,
        IMessageSystemWriter&lt;SayHelloProcessMessage&lt;ProcessActivity&gt;&gt; completedWriter)
        : base(reader)
    {
        <span class="hljs-built_in">this</span>.responseWriter = responseWriter ?? <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentNullException(nameof(responseWriter));
        <span class="hljs-built_in">this</span>.completedWriter = completedWriter ?? <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentNullException(nameof(completedWriter));
    }

    <span class="hljs-keyword">public</span> override <span class="hljs-keyword">async</span> ValueTask HandleAsync(SayHelloProcessMessage&lt;SayHelloResponseActivity&gt; command, CancellationToken stoppingToken)
    {
        <span class="hljs-keyword">var</span> message = $<span class="hljs-string">"Hello there, {command.Input.Name}"</span>;
        <span class="hljs-keyword">await</span> responseWriter.WriteAsync(<span class="hljs-keyword">new</span> SayHelloResponseMessage(message));
        <span class="hljs-keyword">await</span> completedWriter.WriteAsync(<span class="hljs-keyword">new</span> SayHelloProcessMessage&lt;ProcessActivity&gt;(command.ProcessId, command.Phase, command.Input, <span class="hljs-keyword">new</span> SayHelloCompletedActivity()));
    }
}
</code></pre><p>Again all we're doing is implementing the <code>HandleAsync</code> method with our logic which is to simply emit a response message and emit a completed message back to our infrastructure.</p>
<h3 id="the-registrations">The Registrations</h3>
<p>Next we register all our process's components with simple extension method.</p>
<pre><code><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RegistrationExtensions</span>
{</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> IServiceCollection <span class="hljs-title">AddSayHelloProcess</span><span class="hljs-params">(<span class="hljs-keyword">this</span> IServiceCollection services)</span>
        </span>=&gt; services
        .AddWriterProvider()
        .AddProcessStartHandler&lt;SayHelloStartHandler, SayHelloMessageFactory, SayHelloProcessStartMessage, SayHelloEndedMessage, SayHelloInput&gt;()
        .AddPhaseTransitionHandler&lt;SayHelloPhaseTransistionsHandler, SayHelloPhaseTransitions, SayHelloProcessMessage&lt;ProcessActivity&gt;, SayHelloInput&gt;()
        .AddCommandHandler&lt;SayHelloValidationHandler, SayHelloProcessMessage&lt;SayHelloValidation&gt;&gt;()
        .AddCommandHandler&lt;SayHelloResponseHandler, SayHelloProcessMessage&lt;SayHelloResponseActivity&gt;&gt;()
        .AddMessageSystem&lt;SayHelloResponseMessage&gt;()
        .AddMessageSystem&lt;SayHelloProcessStartedMessage&gt;();
}
</code></pre><p>Note how we add dedicated <code>Message Systems</code> for our <code>Started Message</code> and our <code>ResponseMessage</code></p>
<h3 id="the-client-code">The Client Code</h3>
<p>We'll keep our client code simple and not respond to any failure and have it simply timeout if a successful message is not received, in this post we're not interested in elaborate clients. We're simply proving the orchestration of handlers works.</p>
<pre><code>[<span class="hljs-meta">ApiController</span>]
[<span class="hljs-meta">Route(<span class="hljs-meta-string">"[controller]"</span>)</span>]
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">SampleController</span> : <span class="hljs-title">ControllerBase</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IMessageSystemWriter&lt;SayHelloProcessStartMessage&gt; startWriter;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IMessageSystemReader&lt;SayHelloResponseMessage&gt; responseReader;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">SampleController</span>(<span class="hljs-params">
        IMessageSystemWriter&lt;SayHelloProcessStartMessage&gt; startWriter,
        IMessageSystemReader&lt;SayHelloResponseMessage&gt; responseReader</span>)</span>
    {
        <span class="hljs-keyword">this</span>.startWriter = startWriter ?? <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentNullException(<span class="hljs-keyword">nameof</span>(startWriter));
        <span class="hljs-keyword">this</span>.responseReader = responseReader ?? <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentNullException(<span class="hljs-keyword">nameof</span>(responseReader));
    }

    [<span class="hljs-meta">HttpGet</span>]
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> ValueTask&lt;SayHelloResponseMessage&gt; <span class="hljs-title">Get</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> name</span>)</span>
    {
        <span class="hljs-keyword">var</span> startMessage = <span class="hljs-keyword">new</span> SayHelloProcessStartMessage(<span class="hljs-keyword">new</span> SayHelloInput(name));
        <span class="hljs-keyword">await</span> startWriter.WriteAsync(startMessage);
        <span class="hljs-keyword">using</span> <span class="hljs-keyword">var</span> readTokenSource = <span class="hljs-keyword">new</span> CancellationTokenSource();
        readTokenSource.CancelAfter(TimeSpan.FromSeconds(<span class="hljs-number">1</span>));
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> responseReader.ContinuousWaitAndReadAllAsync(readTokenSource.Token).FirstAsync();
    }
}
</code></pre><p>Here we take a writer for the <code>Start Message</code> and pass our input. We also take a reader for the output and provide a <code>CancellationToken</code> to timeout the request if anything fails. We also don't distinguish between <code>Response Messages</code> for individual requests, we could identify them by <code>Process Id</code> but we'll leave that for next time.</p>
<p>And finally we can try everything out and receive a response!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1625523657088/9HP84rP1g.png" alt="Hello World.PNG" /></p>
<h1 id="summary">Summary</h1>
<p>Here we've defined a generic infrastructure to orchestrate complex processes based on two handlers, two dictionaries and a set of messages. The beautiful thing about this system is that it can fundamentally be used with any underlying transport. Complex process are broken down into simple phases, messages and transitions.</p>
<p>Well I hoped you enjoyed my latest. As always the full code can be found at <a target="_blank" href="https://github.com/ptsteward/ConcurrentFlows.HashNode/tree/master/ConcurrentFlows.ProcessManagement">ConcurrentFlows.HashNode GitHub</a></p>
]]></content:encoded></item><item><title><![CDATA[A Simple Hosted Actor System]]></title><description><![CDATA[Overview
Take an AspNet Core Api, for example, we have chosen for this; a pattern of Queries/Commands and Handlers. We're going to explore this pattern and see what we can add to the body of knowledge. When implementing the Command/Query/Handler patt...]]></description><link>https://concurrentflows.com/a-simple-hosted-actor-system</link><guid isPermaLink="true">https://concurrentflows.com/a-simple-hosted-actor-system</guid><category><![CDATA[C#]]></category><category><![CDATA[messaging]]></category><category><![CDATA[asp.net core]]></category><category><![CDATA[design patterns]]></category><dc:creator><![CDATA[Joshua Steward]]></dc:creator><pubDate>Sun, 20 Jun 2021 21:39:14 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1624224253856/3cJRMlAgR.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="overview">Overview</h1>
<p>Take an AspNet Core Api, for example, we have chosen for this; a pattern of Queries/Commands and Handlers. We're going to explore this pattern and see what we can add to the body of knowledge. When implementing the Command/Query/Handler pattern we often end up with many small classes and specialized handlers. This is great for testing and can lead to excellent code organization and separation of concerns. But when integrating with Controllers we find the many handlers need to be injected and we tend towards the mediator pattern. One great implementation of this is <a target="_blank" href="https://github.com/jbogard/MediatR">MediatR</a>, or you can go a similar route taken by one of the great maintainers of <a target="_blank" href="https://github.com/simpleinjector/SimpleInjector">SimpleInjector</a>, who proposes a simple query dispatcher in the great post <a target="_blank" href="https://blogs.cuttingedge.it/steven/posts/2011/meanwhile-on-the-query-side-of-my-architecture/">Meanwhile... on the query side of my architecture</a>. While that post is dated all the way back to 2011, it's still a fantastic reference for what I refer to as <code>Application Scale CQRS</code>. </p>
<h1 id="cqrs-at-different-levels">CQRS At Different Levels</h1>
<p>The Command Query Responsibility Segregation principles can be applied at various levels of your architecture. At the <code>Systems Level</code> we see <a target="_blank" href="https://martinfowler.com/eaaDev/EventSourcing.html">Event Sourcing</a> and a separation of read/write data models. But at the <code>Application Scale</code> we see a breakdown of classes. From monolithic <code>Services</code> and <code>Repositories</code> to single purpose <code>Handlers</code>. This provides a great separation of concerns and extensibility while keeping code cohesive within a single domain.</p>
<h1 id="the-dispatch-issue">The Dispatch Issue</h1>
<p>One common problem we find in the <a target="_blank" href="https://dotnetcoretutorials.com/2019/04/30/the-mediator-pattern-in-net-core-part-1-whats-a-mediator/">Mediator Pattern</a> is the need to dynamically invoke un-instantiated handlers at runtime. Even with the super fast <a target="_blank" href="https://github.com/simpleinjector/SimpleInjector">SimpleInjector</a> this can take time especially if we're invoking a complex web of handlers to accomplish a given task. So the question becomes how can we retain the benefits of <code>Application Scale CQRS</code> while avoiding the runtime costs of instantiation of handlers.</p>
<h1 id="the-actor-pattern">The Actor Pattern</h1>
<p>The <a target="_blank" href="https://mattferderer.com/what-is-the-actor-model-and-when-should-you-use-it">Actor Pattern</a> represents a shift in thinking. Instead of request scoped handlers I propose a pool of interconnected  communicating handlers. While <code>Matt Ferderer</code> defines the properties of an actor to include:</p>
<ul>
<li>Store Data </li>
<li>Receive messages from other actors</li>
<li>Pass messages to other actors</li>
<li>Create additional child actors</li>
</ul>
<p>I'm going to take a different angle.</p>
<h1 id="our-goals-a-simple-hosted-actor-system">Our Goals: A simple hosted actor system</h1>
<p>I'm going to redefine an <code>Actor</code> a little a differently for our api specific use case, an <code>Actor</code> should:</p>
<ul>
<li>Live outside the request stream</li>
<li>Be able to receive messages asynchronously</li>
<li>Return a result asynchronously</li>
<li>Communicate with other actors in the system without instantiating them</li>
<li>Finally, be decoupled from the calling code</li>
</ul>
<p>In order to achieve these goals we're going to combine elements of the <code>Mediator Pattern</code> and the <code>Actor Pattern</code>. And just for examples sake we're going to focus on the Query side of CQRS, the Command side is much simpler and maybe the topic of a future post.</p>
<h1 id="our-solution">Our Solution</h1>
<h2 id="the-basic-infrastrucuture">The Basic Infrastrucuture</h2>
<p>First we start with the basic infrastructure that will make up our system. You surely have seen many iterations of <code>IQuery</code>, <code>IQueryHandler</code> , etc. However, we're going to change them slightly to fit with our <code>Actor</code> approach. For starters we define an <code>ActorQuery</code> as such:</p>
<pre><code><span class="hljs-keyword">namespace</span> <span class="hljs-title">ConcurrentFlows.HostedActorSystem.ActorSystem.Infrastructure</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> record <span class="hljs-title">ActorQuery</span>&lt;<span class="hljs-title">TPayload</span>, <span class="hljs-title">TAnswer</span>&gt;(<span class="hljs-params">TPayload Payload</span>)</span>;
}
</code></pre><p>Note in this record we define the payload that we will submit to the actor system and we define the type of answer we expect back. We intentionally use the term <code>Answer</code> to distinguish it form a typical <code>Task</code> <code>Result</code>. This aligns more so with the concept of; <strong>Every query has an answer.</strong>
Next we define our base hosted <code>QueryActor</code> this actor will be resoponsible for reciveing the input payload and emitting the answer to the query</p>
<pre><code><span class="hljs-keyword">namespace</span> <span class="hljs-title">ConcurrentFlows.HostedActorSystem.ActorSystem.Infrastructure</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">class</span> <span class="hljs-title">QueryActor</span>&lt;<span class="hljs-title">TQuery</span>&gt;
        : <span class="hljs-title">BackgroundService</span>
    {
        <span class="hljs-keyword">protected</span> <span class="hljs-keyword">readonly</span> ChannelReader&lt;KeyValuePair&lt;Guid, TQuery&gt;&gt; queryReader;
        <span class="hljs-keyword">protected</span> <span class="hljs-keyword">readonly</span> ChannelWriter&lt;KeyValuePair&lt;Guid, <span class="hljs-keyword">dynamic</span>&gt;&gt; answerWriter;

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">QueryActor</span>(<span class="hljs-params">
            ChannelReader&lt;KeyValuePair&lt;Guid, TQuery&gt;&gt; queryReader, 
            ChannelWriter&lt;KeyValuePair&lt;Guid, <span class="hljs-keyword">dynamic</span>&gt;&gt; answerWriter</span>)</span>
        {
            <span class="hljs-keyword">this</span>.queryReader = queryReader ?? <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentNullException(<span class="hljs-keyword">nameof</span>(queryReader));
            <span class="hljs-keyword">this</span>.answerWriter = answerWriter ?? <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentNullException(<span class="hljs-keyword">nameof</span>(answerWriter));
        }

        <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">ExecuteAsync</span>(<span class="hljs-params">CancellationToken stoppingToken</span>)</span>
        {
            <span class="hljs-keyword">while</span> (!stoppingToken.IsCancellationRequested &amp;&amp; !queryReader.Completion.IsCompleted)
            {
                <span class="hljs-keyword">var</span> messageReady = <span class="hljs-keyword">await</span> queryReader.WaitToReadAsync(stoppingToken);
                <span class="hljs-keyword">if</span> (messageReady)
                {
                    <span class="hljs-keyword">await</span> <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> query <span class="hljs-keyword">in</span> queryReader.ReadAllAsync(stoppingToken))
                    {
                        <span class="hljs-keyword">await</span> HandleAsync(query, stoppingToken);
                    }
                }
            }
        }

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> Task <span class="hljs-title">HandleAsync</span>(<span class="hljs-params">KeyValuePair&lt;Guid, TQuery&gt; query, CancellationToken stoppingToken</span>)</span>;
    }
}
</code></pre><p>Our base <code>QueryActor</code> takes a <code>ChannelReader</code> that accepts the input query keyed with a unique identifier. This unique identifier will be used to connect <code>Answers</code> with <code>Queries</code>. We also make use of the dynamic type and an unconstrained query type parameter to allow this base Actor to handle any query and any answer. This approach is shown now in the what connects our Actor System together: the <code>AnswerStream</code>.</p>
<pre><code><span class="hljs-keyword">namespace</span> <span class="hljs-title">ConcurrentFlows.HostedActorSystem.ActorSystem.Infrastructure</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">IAnswerStream</span> : <span class="hljs-title">IHostedService</span>
    {
        <span class="hljs-function"><span class="hljs-title">ValueTask</span>&lt;<span class="hljs-title">dynamic</span>&gt; <span class="hljs-title">SubmitQuery</span>&lt;<span class="hljs-title">TQuery</span>&gt;(<span class="hljs-params">TQuery query</span>)</span>;
    }
}
</code></pre><p>First we've defined a simple interface to interact with our Actor System. This interface allows us to submit a query and await a result from Actor System. Notice also that we e're extending the <code>IHostedService</code> interface to allow this stream to live outside the request scope and serve it's primary purpose of matching <code>Answers</code> to <code>Queries</code></p>
<pre><code><span class="hljs-keyword">namespace</span> <span class="hljs-title">ConcurrentFlows.HostedActorSystem.ActorSystem.Infrastructure</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">AnswerStream</span> : <span class="hljs-title">BackgroundService</span>, <span class="hljs-title">IAnswerStream</span>
    {
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IServiceProvider serviceProvider;
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ChannelReader&lt;KeyValuePair&lt;Guid, <span class="hljs-keyword">dynamic</span>&gt;&gt; answerReader;

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">AnswerStream</span>(<span class="hljs-params">
            IServiceProvider serviceProvider, 
            ChannelReader&lt;KeyValuePair&lt;Guid, <span class="hljs-keyword">dynamic</span>&gt;&gt; answerReader</span>)</span>
        {
            <span class="hljs-keyword">this</span>.serviceProvider = serviceProvider ?? <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentNullException(<span class="hljs-keyword">nameof</span>(serviceProvider));
            <span class="hljs-keyword">this</span>.answerReader = answerReader ?? <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentNullException(<span class="hljs-keyword">nameof</span>(answerReader));
            QueryResults = <span class="hljs-keyword">new</span> ConcurrentDictionary&lt;Guid, TaskCompletionSource&lt;<span class="hljs-keyword">dynamic</span>&gt;&gt;();
        }

        <span class="hljs-keyword">private</span> ConcurrentDictionary&lt;Guid, TaskCompletionSource&lt;<span class="hljs-keyword">dynamic</span>&gt;&gt; QueryResults { <span class="hljs-keyword">get</span>; }

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> <span class="hljs-title">ValueTask</span>&lt;<span class="hljs-title">dynamic</span>&gt; <span class="hljs-title">SubmitQuery</span>&lt;<span class="hljs-title">TQuery</span>&gt;(<span class="hljs-params">TQuery query</span>)</span>
        {
            <span class="hljs-keyword">var</span> writer = serviceProvider.GetRequiredService&lt;ChannelWriter&lt;KeyValuePair&lt;Guid, TQuery&gt;&gt;&gt;();
            <span class="hljs-keyword">var</span> queryId = Guid.NewGuid();
            <span class="hljs-keyword">var</span> resultSource = <span class="hljs-keyword">new</span> TaskCompletionSource&lt;<span class="hljs-keyword">dynamic</span>&gt;();
            QueryResults.TryAdd(queryId, resultSource);
            <span class="hljs-keyword">await</span> writer.WriteAsync(<span class="hljs-keyword">new</span> KeyValuePair&lt;Guid, TQuery&gt;(queryId, query));
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> resultSource.Task;
        }

        <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">ExecuteAsync</span>(<span class="hljs-params">CancellationToken stoppingToken</span>)</span>
        {
            <span class="hljs-keyword">while</span> (!stoppingToken.IsCancellationRequested &amp;&amp; !answerReader.Completion.IsCompleted)
            {
                <span class="hljs-keyword">var</span> resultsReady = <span class="hljs-keyword">await</span> answerReader.WaitToReadAsync(stoppingToken);
                <span class="hljs-keyword">if</span> (resultsReady)
                    <span class="hljs-keyword">await</span> <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> result <span class="hljs-keyword">in</span> answerReader.ReadAllAsync(stoppingToken))
                        <span class="hljs-keyword">if</span> (QueryResults.TryRemove(result.Key, <span class="hljs-keyword">out</span> <span class="hljs-keyword">var</span> resultSource))
                            resultSource.TrySetResult(result.Value);
            }
        }
    }
}
</code></pre><p>We see in this implementation the only use of runtime resolution is the instantiation of a singleton <code>ChannelWriter</code> to input the supplied query into our Actor System. This is a low cost operation since the <code>ChannelWriter</code> will be held and made available as a singleton in our <code>ServiceProvider</code>. We see also, that when a query is submitted it is asigned an unquie identifer that will later be used to match it up with its results, it is also associated with a <code>TaskCompletionSource&lt;TAnswer&gt;</code> and this associated <code>Task</code> is returned to the caller to await the results from our <code>AnswerStream</code>. The <code>ExecuteAsync</code> method continuously waits for results to match up with assigned queries and manages the <code>ConcurrentDictionary</code> that stores the associated <code>TaskCompletionSources</code>. And again, we use dynamic for the answer type to allow this <code>AnswerStream</code> to handle any query and any <code>Answer</code>. More could be done here to better manage the <code>ConcurrentDictionary</code> but this is just basic working sample.</p>
<p>The Last piece of infrastructure we need is way to register our actor system with the <code>ServiceProvider</code>. To accomplish that we create an extension method to add all the necessary bit and pieces to our DI.</p>
<pre><code><span class="hljs-keyword">namespace</span> <span class="hljs-title">ConcurrentFlows.HostedActorSystem.ActorSystem.Infrastructure</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title">RegistrationExtensions</span>
    {
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> IServiceCollection <span class="hljs-title">AddActor</span>&lt;<span class="hljs-title">TActor</span>, <span class="hljs-title">TQuery</span>&gt;(<span class="hljs-params"><span class="hljs-keyword">this</span> IServiceCollection services</span>)
            <span class="hljs-keyword">where</span> TActor : QueryActor&lt;TQuery&gt;</span>
        {            
            services.AddHostedService&lt;TActor&gt;();
            <span class="hljs-keyword">var</span> inputChannel = Channel.CreateUnbounded&lt;KeyValuePair&lt;Guid, TQuery&gt;&gt;();
            services.AddSingleton(inputChannel.Writer);
            services.AddSingleton(inputChannel.Reader);            
            <span class="hljs-keyword">return</span> services;
        }

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> IServiceCollection <span class="hljs-title">AddAnswerStream</span>(<span class="hljs-params"><span class="hljs-keyword">this</span> IServiceCollection services</span>)</span>
        {
            services.AddSingleton&lt;IAnswerStream, AnswerStream&gt;();
            services.AddHostedService(sp =&gt; sp.GetRequiredService&lt;IAnswerStream&gt;());
            <span class="hljs-keyword">var</span> answerChannel = Channel.CreateUnbounded&lt;KeyValuePair&lt;Guid, <span class="hljs-keyword">dynamic</span>&gt;&gt;();
            services.AddSingleton(answerChannel.Writer);
            services.AddSingleton(answerChannel.Reader);
            <span class="hljs-keyword">return</span> services;
        }
    }
}
</code></pre><p>This extension registers:</p>
<ul>
<li>Our <code>AnswerStream</code></li>
<li>Our input <code>Channels</code></li>
<li>Our answer <code>Channels</code></li>
<li>And of course our <code>Actor</code> implementation.</li>
</ul>
<h2 id="sample-demo">Sample Demo</h2>
<h3 id="the-input-side">The Input Side</h3>
<p>For demonstration of this system we are going to query for the <a target="_blank" href="https://en.wikipedia.org/wiki/Factorial">factorial</a> of a given number. And as an example of utilizing multiple types we'll return an input message. We start with the api queries that is received through our RESTish interface.</p>
<pre><code><span class="hljs-keyword">namespace</span> <span class="hljs-title">ConcurrentFlows.HostedActorSystem.Queries.Api</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> record <span class="hljs-title">GetFactorialApiQuery</span>(<span class="hljs-params">[FromQuery] <span class="hljs-keyword">int</span> Message</span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">public</span> record <span class="hljs-title">GetMessageApiQuery</span>(<span class="hljs-params">[FromQuery]<span class="hljs-keyword">string</span> Message</span>)</span>;
}
</code></pre><p>Notice how we're not only making use of the new <code>Record</code> types here but also <code>Record</code> model binding in our controller.</p>
<pre><code><span class="hljs-keyword">namespace</span> <span class="hljs-title">ConcurrentFlows.HostedActorSystem.Controllers</span>
{
    [<span class="hljs-meta">ApiController</span>]
    [<span class="hljs-meta">Route(<span class="hljs-meta-string">"[controller]"</span>)</span>]
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">SampleController</span> : <span class="hljs-title">ControllerBase</span>
    {
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IAnswerStream answerStream;

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">SampleController</span>(<span class="hljs-params">IAnswerStream answerStream</span>)</span>
            =&gt; <span class="hljs-keyword">this</span>.answerStream = answerStream ?? <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentNullException(<span class="hljs-keyword">nameof</span>(answerStream));

        [<span class="hljs-meta">HttpGet</span>]
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;IActionResult&gt; <span class="hljs-title">GetFactorial</span>(<span class="hljs-params">[FromQuery] GetFactorialApiQuery query</span>)</span>
        {
            <span class="hljs-keyword">var</span> actorQuery = <span class="hljs-keyword">new</span> GetFactorialActorQuery(query.Message);
            <span class="hljs-keyword">var</span> result = <span class="hljs-keyword">await</span> answerStream.SubmitQuery(actorQuery);
            <span class="hljs-keyword">return</span> Ok(result);
        }

        [<span class="hljs-meta">HttpGet(<span class="hljs-meta-string">"message"</span>)</span>]
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;IActionResult&gt; <span class="hljs-title">ReturnMessage</span>(<span class="hljs-params">[FromQuery] GetMessageApiQuery query</span>)</span>
        {
            <span class="hljs-keyword">var</span> actorQuery = <span class="hljs-keyword">new</span> GetMessageActorQuery(query.Message);
            <span class="hljs-keyword">var</span> result = <span class="hljs-keyword">await</span> answerStream.SubmitQuery(actorQuery);
            <span class="hljs-keyword">return</span> Ok(result);
        }
    }
}
</code></pre><p>Our controller takes the input api query, translates it to an <code>ActorQuery</code> and submits it to our system. It also gets injected with an <code>AnswerStream</code> that will provide access to the Actor System and the result from the query.</p>
<h3 id="interconnected-actors">Interconnected Actors</h3>
<p>The factorial query in particular is an<code>ActorQuery</code> that is a system of two interconnected actors that are invoked with these two queries.</p>
<pre><code><span class="hljs-built_in">public</span> <span class="hljs-type">record</span> GetFactorialActorQuery(<span class="hljs-type">int</span> Payload) : ActorQuery&lt;<span class="hljs-type">int</span>, <span class="hljs-type">int</span>&gt;(Payload);
<span class="hljs-built_in">public</span> <span class="hljs-type">record</span> GetReverseRangeActorQuery(<span class="hljs-type">int</span> Payload) : ActorQuery&lt;<span class="hljs-type">int</span>, IAsyncEnumerable&lt;<span class="hljs-type">int</span>&gt;&gt;(Payload);
</code></pre><p>These queries invoke two interconnected actors which cooperate to produce a result. The deepest Actor is the <code>ReverseRangeQueryActor</code>. This Actor has the responsibility of producing a range of int's in reverse order.</p>
<pre><code><span class="hljs-keyword">namespace</span> <span class="hljs-title">ConcurrentFlows.HostedActorSystem.ActorSystem.Actors</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">GetReverseRangeQueryActor</span> : <span class="hljs-title">QueryActor</span>&lt;<span class="hljs-title">GetReverseRangeActorQuery</span>&gt;
    {
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">GetReverseRangeQueryActor</span>(<span class="hljs-params">
            ChannelReader&lt;KeyValuePair&lt;Guid, GetReverseRangeActorQuery&gt;&gt; queryReader,
            ChannelWriter&lt;KeyValuePair&lt;Guid, <span class="hljs-keyword">dynamic</span>&gt;&gt; answerWriter</span>)
            : <span class="hljs-title">base</span>(<span class="hljs-params">queryReader, answerWriter</span>)</span>
        {

        }

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">HandleAsync</span>(<span class="hljs-params">KeyValuePair&lt;Guid, GetReverseRangeActorQuery&gt; query, CancellationToken stoppingToken</span>)</span>
        {
            <span class="hljs-keyword">var</span> range = Enumerable.Range(<span class="hljs-number">1</span>, query.Value.Payload).Reverse().ToAsyncEnumerable();
            <span class="hljs-keyword">var</span> answer = <span class="hljs-keyword">new</span> KeyValuePair&lt;Guid, <span class="hljs-keyword">dynamic</span>&gt;(query.Key, range);
            <span class="hljs-keyword">await</span> answerWriter.WriteAsync(answer);
        }
    }
}
</code></pre><p>Notice how this Actor keys the results with the same key provided in the input.</p>
<p>The next Actor up is the <code>FactorialQueryActor</code>. This Actor takes the input value from the query, the range provided by the <code>ReverseRangeQueryActor</code> and computes the factorial.</p>
<pre><code><span class="hljs-keyword">namespace</span> <span class="hljs-title">ConcurrentFlows.HostedActorSystem.ActorSystem.Actors</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">GetFactorialQueryActor</span> : <span class="hljs-title">QueryActor</span>&lt;<span class="hljs-title">GetFactorialActorQuery</span>&gt;
    {
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IAnswerStream actorStream;

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">GetFactorialQueryActor</span>(<span class="hljs-params">
            ChannelReader&lt;KeyValuePair&lt;Guid, GetFactorialActorQuery&gt;&gt; queryReader,
            ChannelWriter&lt;KeyValuePair&lt;Guid, <span class="hljs-keyword">dynamic</span>&gt;&gt; answerWriter,
            IAnswerStream actorStream</span>)
            : <span class="hljs-title">base</span>(<span class="hljs-params">queryReader, answerWriter</span>)</span>
        {
            <span class="hljs-keyword">this</span>.actorStream = actorStream ?? <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentNullException(<span class="hljs-keyword">nameof</span>(actorStream));
        }

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">HandleAsync</span>(<span class="hljs-params">KeyValuePair&lt;Guid, GetFactorialActorQuery&gt; query, CancellationToken stoppingToken</span>)</span>
        {
            <span class="hljs-keyword">var</span> rangeQuery = <span class="hljs-keyword">new</span> GetReverseRangeActorQuery(query.Value.Payload - <span class="hljs-number">1</span>);
            IAsyncEnumerable&lt;<span class="hljs-keyword">int</span>&gt; result = <span class="hljs-keyword">await</span> actorStream.SubmitQuery(rangeQuery);
            <span class="hljs-keyword">var</span> factorial = <span class="hljs-keyword">await</span> result.AggregateAsync(query.Value.Payload, (x, y) =&gt; x * y);
            <span class="hljs-keyword">var</span> answer = <span class="hljs-keyword">new</span> KeyValuePair&lt;Guid, <span class="hljs-keyword">dynamic</span>&gt;(query.Key, factorial);
            <span class="hljs-keyword">await</span> answerWriter.WriteAsync(answer);
        }
    }
}
</code></pre><p>Notice how these Actors are connected using the very same <code>AnswerStream</code> setup that's used to communicate from the controller to the Actor System. The <code>AnswerStream</code> integrates the Actor System so that all Actors can communicate asynchronously without any knowledge of each other except for the defined Query types, just like our standard Application Level CQRS. This leaves us completely decoupled by the queries.</p>
<h3 id="our-other-actor">Our Other Actor</h3>
<p>The <code>GetMessageActorQuery</code> simply returns the input message.</p>
<pre><code><span class="hljs-keyword">namespace</span> <span class="hljs-title">ConcurrentFlows.HostedActorSystem.ActorSystem.Actors</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">GetMessageQueryActor</span> : <span class="hljs-title">QueryActor</span>&lt;<span class="hljs-title">GetMessageActorQuery</span>&gt;
    {
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">GetMessageQueryActor</span>(<span class="hljs-params">
            ChannelReader&lt;KeyValuePair&lt;Guid, GetMessageActorQuery&gt;&gt; queryReader,
            ChannelWriter&lt;KeyValuePair&lt;Guid, <span class="hljs-keyword">dynamic</span>&gt;&gt; answerWriter</span>)
            : <span class="hljs-title">base</span>(<span class="hljs-params">queryReader, answerWriter</span>)</span>
        {

        }

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">HandleAsync</span>(<span class="hljs-params">KeyValuePair&lt;Guid, GetMessageActorQuery&gt; query, CancellationToken stoppingToken</span>)</span>
        {
            <span class="hljs-keyword">await</span> answerWriter.WriteAsync(<span class="hljs-keyword">new</span> KeyValuePair&lt;Guid, <span class="hljs-keyword">dynamic</span>&gt;(query.Key, query.Value.Payload));
        }
    }
}
</code></pre><h3 id="configureservices-the-last-piece-of-the-puzzle">ConfigureServices: The last piece of the puzzle</h3>
<p>The last final piece to show is the simple registration of all our actors.</p>
<pre><code><span class="hljs-keyword">public</span> <span class="hljs-built_in">void</span> ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
    services.AddSwaggerGen(<span class="hljs-function"><span class="hljs-params">c</span> =&gt;</span>
    {
        c.SwaggerDoc(<span class="hljs-string">"v1"</span>, <span class="hljs-keyword">new</span> OpenApiInfo { Title = <span class="hljs-string">"ConcurrentFlows.HostedActorSystem"</span>, Version = <span class="hljs-string">"v1"</span> });
    });
    services.AddAnswerStream();
    services.AddActor&lt;GetFactorialQueryActor, GetFactorialActorQuery&gt;();
    services.AddActor&lt;GetReverseRangeQueryActor, GetReverseRangeActorQuery&gt;();
    services.AddActor&lt;GetMessageQueryActor, GetMessageActorQuery&gt;();
}
</code></pre><p>And now with everything in place we can test our simple Hosted Actor System and get a result!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1624221769820/bMhHPJhFN.png" alt="ActorSystemOutput.PNG" /></p>
<h1 id="summary">Summary</h1>
<p>How cool was that! I don't know about you but that simple answer is pretty satisfying! We've created a simple Hosted Actor System to replace our request scoped <code>Handlers</code>. Our Actors communicate completely asynchronously and without knowledge of one another through our <code>AnswerStream</code>. These Actors live outside the request scope along with our <code>AnswerStream</code>. Always ready and able to process incoming requests in an asynchronous decoupled manner. Kinda beautiful in a way! <strong>Now I'm not saying go out and replace your architecture with this style but only to consider this simple Hosted Actor pattern when the problem space warrants it.</strong></p>
<p>You can find all code <a target="_blank" href="https://github.com/ptsteward/ConcurrentFlows.HashNode/tree/master/ConcurrentFlows.HostedActorSystem">GitHub ConcurrentFlows.HashNode</a></p>
]]></content:encoded></item></channel></rss>