<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Mateus Viegas</title>
    <description>The latest articles on Forem by Mateus Viegas (@mviegas).</description>
    <link>https://forem.com/mviegas</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F252503%2Fa7666215-9ec2-4075-ae79-653fc344df26.jpeg</url>
      <title>Forem: Mateus Viegas</title>
      <link>https://forem.com/mviegas</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/mviegas"/>
    <language>en</language>
    <item>
      <title>Messaging: an Introduction</title>
      <dc:creator>Mateus Viegas</dc:creator>
      <pubDate>Sun, 21 Feb 2021 18:16:00 +0000</pubDate>
      <link>https://forem.com/mviegas/messaging-an-introduction-2a5e</link>
      <guid>https://forem.com/mviegas/messaging-an-introduction-2a5e</guid>
      <description>&lt;h1&gt;
  
  
  &lt;em&gt;tl/dr&lt;/em&gt;
&lt;/h1&gt;

&lt;p&gt;This post is the first one of a series about basic concepts within distributed architectures. &lt;/p&gt;

&lt;p&gt;1) Messaging: An introduction&lt;/p&gt;

&lt;p&gt;2) Messaging: Practical basic concepts with System.Threading.Channels&lt;/p&gt;

&lt;p&gt;3) Messaging: Interaction Styles&lt;/p&gt;

&lt;p&gt;4) Messaging: Consistency and Resiliency Patterns&lt;/p&gt;

&lt;p&gt;The goal of this series is to provide new venturers on distributed systems world with basic concepts of messaging, the tradeoffs of this kind of resource and how to provide solutions for some of these tradeoffs in order to achieve the most important benefit of messaging: loose coupling and high scalability within a distributed architecture.&lt;/p&gt;

&lt;p&gt;Messaging is one of the pillars for this kind of architecture to be sustainable. Here we will showcase basic theoretical concepts such as Messages and their types, as well as Transport Channels and their types. Also, we will give a high level overview about when you should or shouldn't consider messaging.&lt;/p&gt;

&lt;h1&gt;
  
  
  Loose coupling, but why?
&lt;/h1&gt;

&lt;p&gt;First things first: we can define messaging as a way of communication between two or more resources. In this manner, these resources communicate by sending and receiving &lt;em&gt;messages&lt;/em&gt; through a &lt;em&gt;messaging infrastructure&lt;/em&gt; instead of doing direct and synchronous requests to each other.&lt;/p&gt;

&lt;p&gt;This is achieved by the exchange of &lt;em&gt;messages&lt;/em&gt; via one or more &lt;em&gt;message channels&lt;/em&gt;: a sender, which is some component within a system, writes messages to a channel inside this messaging infrastructure, and a receiver, another component, reads messages coming in via this channel. Thus, when messaging is introduced and sync communication is removed, we also remove direct coupling between these components. We can say then that these components are &lt;strong&gt;loosely coupled&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;As pretty as it might seems, one question remains though: why would we want to make components within a system loosely coupled? To answer that question, let's understand one specific type of coupling that might be the greatest reason for using messaging and distributing a system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Temporal coupling
&lt;/h2&gt;

&lt;p&gt;An application usually has some IO-bounded dependencies such as disks and networks. These dependencies might be databases, calls to external APIs, email sender services, file storages, or even some other external system, etc. Each time a request cross an IO boundary, it will have its response coupled to the result/response of this initiated IO operation. &lt;/p&gt;

&lt;p&gt;Even with modern concepts such as Task-based programming in C#, the so called &lt;em&gt;asynchronous&lt;/em&gt; code is, de facto, async only from a thread perspective. This means, that applications like a web API, will still have the incoming requests waiting for each one of these async blocks of code to complete in order respond the client. The asynchronicity mentioned here relies on how these requests are executed from a thread perspective, meaning they are async because they do not lock the calling thread, a CPU resource, while IO operations are in place. What happens is that the application, when calling an &lt;code&gt;async&lt;/code&gt; code, passes the responsibility of the execution continuation to another thread and frees up the calling one. This is actually really important, since there's a limited number of threads to execute CPU-bounded operations on the thread pool. Imagine the following situation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There's an incoming request;&lt;/li&gt;
&lt;li&gt;This request does a query to the database and return a response with the result;

&lt;ul&gt;
&lt;li&gt;Since database queries are IO operations, the calling thread might be blocked while awaiting for the database to execute the query. In this case, imagine that there are multiple requests coming in and that the database is, by some reason, overloaded and not responding properly. Since the number of CPU-bounded threads is limited, there might come a time when there's no more free threads to handle incoming requests: &lt;a href="https://www.geeksforgeeks.org/deadlock-starvation-and-livelock/" rel="noopener noreferrer"&gt;starvation happens&lt;/a&gt;. In this case, the application might be unresponsive or with a very high response times for new requests, since there are no more free threads to execute and it has to wait more threads to be available.&lt;/li&gt;
&lt;li&gt;Now, imagine that these incoming requests access the database via an &lt;code&gt;async&lt;/code&gt; method that executes the query. When that happens, a state machine is created with the request context and the control of this state machine is passed to a new thread, so that the CPU-bounded calling thread gets free to be used by any other incoming request. This another IO-bounded thread executes its operation on the database and, since it has this state machine, it is able to provide a &lt;em&gt;continuation&lt;/em&gt; to the request through a &lt;em&gt;synchronisation context&lt;/em&gt;, a.k.a., returning a response to the API with the query result. In this case, we give some buffer for our application performance, allowing our thread pool to have the incoming threads relying on CPU-bounded work only and being released more frequently to handle new requests.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Tl/dr: this whole explanation was to clarify that executions with the &lt;code&gt;async&lt;/code&gt; keyword are, from a &lt;em&gt;temporal&lt;/em&gt; perspective, still synchronous. The overall response time still depends on the database execution. Or, perhaps, on another external and unstable web API/system. And that's why this type of coupling is called &lt;strong&gt;temporal coupling&lt;/strong&gt; and might be an issue if you need an application to have fast response times.&lt;/p&gt;

&lt;p&gt;Messaging allows us to remove temporal coupling by deferring requests to be executed either in background or by third-party applications. In this case, a system component sends a message containing some sort of data through a channel and another system component, which is connected to this channel, receives this message and execute. Therefore, the component that sends the message is temporally coupled only to the message dispatching and not to an entire ecosystem of dependencies that there might exist.&lt;/p&gt;

&lt;h1&gt;
  
  
  Message Types
&lt;/h1&gt;

&lt;p&gt;Messages are chunks of data structured with both a &lt;em&gt;body&lt;/em&gt; and also some &lt;em&gt;headers&lt;/em&gt;. The body contains the central information and the message &lt;em&gt;payload&lt;/em&gt;, and the headers might have some really useful metadata such as an &lt;em&gt;unique message identifier&lt;/em&gt;, one or more &lt;em&gt;correlation identifiers&lt;/em&gt; that could be used to correlate operations on different systems, etc. What's important to understand here is: messages are literally DTOs (data transfer objects). These DTOs are then serialised and sent via a channel. Either in JSON, binary, XML or any other format.&lt;/p&gt;

&lt;p&gt;It is also common to think about messages from a semantic point of view, giving them &lt;em&gt;meaning&lt;/em&gt;. This allows them to be categorised into types. Some of the most popular message types are &lt;em&gt;commands&lt;/em&gt; and &lt;em&gt;events&lt;/em&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Commands
&lt;/h2&gt;

&lt;p&gt;Commands can be understood as requests specifications. A descriptive method name with zero or more parameters. Imagine, for instance, a &lt;code&gt;CreateUserCommand&lt;/code&gt;. This command might have some parameters such as &lt;code&gt;Email&lt;/code&gt; and &lt;code&gt;Password&lt;/code&gt;. We could describe this message as the following class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CreateUserCommand&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Email&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Password&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When this class is sent over a channel, the recipient system would then read this specification and execute the operation. The meaning of a command is basically &lt;em&gt;"do something with these attributes"&lt;/em&gt;, in this case, this message is telling to the recipient: &lt;em&gt;"create a user with this email and this password"&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Events
&lt;/h2&gt;

&lt;p&gt;On the other hand, we have &lt;em&gt;events&lt;/em&gt;, that indicates and describe something that happened within the system. So for a &lt;code&gt;CreateUserCommand&lt;/code&gt;, we could have a &lt;code&gt;UserCreatedEvent&lt;/code&gt; describing a side-effect on our system, result from a previous operation. In this particular case, the event would be pretty similar to the command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserCreatedEvent&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Email&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You could read this as "an user was created with this email". This information could then be broadcasted via messaging, so that any other interested part of the system could receive this information and do something about it, like sending a welcome email, for instance.&lt;/p&gt;

&lt;h1&gt;
  
  
  Channels
&lt;/h1&gt;

&lt;p&gt;The &lt;a href="https://www.amazon.com/o/asin/0321200683/ref=nosim/enterpriseint-20" rel="noopener noreferrer"&gt;Enterprise Integration Patterns book&lt;/a&gt; has the following description about channels: &lt;em&gt;"when an application has information to communicate, it doesn't just fling the information into the messaging system, it adds the information to a particular Message Channel. An application receiving information doesn't just pick it up at random from the messaging system; it retrieves the information from a particular Message Channel."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.enterpriseintegrationpatterns.com%2Fimg%2FMessageChannelSolution.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.enterpriseintegrationpatterns.com%2Fimg%2FMessageChannelSolution.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are mainly two types of message channels:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Point-to-point: this type of channel delivers the message to exactly one, and only one, consumer that is listening to the channel. If there are multiple consumers, it means that they will concur for the incoming messages and each message will only be read by one consumer. To have multiple and competing consumers in a point-to-point channel could be useful to increase the throughput of the channel, if we have a lot of messages being sent to it, and is basically a way of scaling the message consumption. Commands are often sent through this type of channel.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Publish-subscribe: this type of channel might have multiple consumers that receive, each one, a copy of the message. This type of channel is particularly good for some scenarios. With &lt;em&gt;pub/sub&lt;/em&gt; we can easily move information around many interested parties with no temporal coupling between them. One system X can know what happens to other system Y by receiving messages sent by Y to a message channel that X, by its turn, is listening to. That way, we can easily move information around many components within a system with no tight coupling between them, making the integration process between these components smoother. Events are often sent through this type of channel.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  First trade-offs
&lt;/h1&gt;

&lt;p&gt;Even though messaging is often referred as a way of integrating and remove coupling between distributed systems, we can use the same concept to extend functionality inside one single system. By using the concept of commands and events within an application, we can easily expand its features without changing existing ones. I talk a little bit more about it in an old post about the correlation between &lt;a href="https://dev.to/mviegas/a-brief-brainstorm-about-the-open-closed-principle-and-event-driven-architectures-323h"&gt;"the open-closed principle and event-driven architectures"&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;However, just as anything regarding to software engineering and architecture, messaging has its trade-offs. By delegating the message handling to an external consumer via a message channel we introduce a &lt;strong&gt;single point of failure&lt;/strong&gt;: the messaging infrastructure. A single point of failure, commonly named SPOF, it is a component within a system that, if fails, will stop the entire system of working. &lt;/p&gt;

&lt;p&gt;Therefore, since all the communication between the systems rely on a central piece of communication, the messaging infrastructure, it becomes a requirement that this piece has a very high level of availability. &lt;/p&gt;

&lt;p&gt;There are still many other trade-offs of applying messaging and distributing your system, such as maintenance, monitoring and development complexity introduced by many side-effects caused by the decoupling, and we will talk more in detail about them on the next posts of this series. &lt;/p&gt;

&lt;h1&gt;
  
  
  Wrap-up
&lt;/h1&gt;

&lt;p&gt;Messages are a nice concept and are very fundamental when we talk about distributed systems and architectures. The concept itself is an abstraction, which implementations are diverse, as well as the possible infrastructure resources to handle it. &lt;/p&gt;

&lt;p&gt;In this introductory post, we showcased how we exchange temporal for loose coupling with messaging, and why it might be good. We also introduced basic message types, channel types and also discussed briefly about the consequences of introducing messaging to a system.&lt;/p&gt;

&lt;p&gt;On the next post will showcase an abstraction of the concepts showcased here: we will remove temporal coupling in a web API by sending messages via channels created with C# and the &lt;em&gt;System.Threading.Channels&lt;/em&gt; library.&lt;/p&gt;

</description>
      <category>distributedsystems</category>
      <category>architecture</category>
      <category>microservices</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>A brief brainstorm about the open-closed principle and event-driven architectures</title>
      <dc:creator>Mateus Viegas</dc:creator>
      <pubDate>Thu, 04 Jun 2020 19:38:12 +0000</pubDate>
      <link>https://forem.com/mviegas/a-brief-brainstorm-about-the-open-closed-principle-and-event-driven-architectures-323h</link>
      <guid>https://forem.com/mviegas/a-brief-brainstorm-about-the-open-closed-principle-and-event-driven-architectures-323h</guid>
      <description>&lt;h1&gt;
  
  
  &lt;strong&gt;tl/dr&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;The &lt;em&gt;open-closed principle&lt;/em&gt;, one of the SOLID ones, states that one system/module/program should be "open for extension, but closed for modification." I've always found the statement itself quite vague. In this post, we are going to discuss in a little more practical way what it might mean from a practical point of view, both in code and architecture perspectives. We're going to talk about some specific concerns here, such as Domain-Driven Design, Pub/Sub and Message Brokers, so it might be useful to at least make yourself familiar with these concepts first.&lt;/p&gt;

&lt;h1&gt;
  
  
  Giving meaning to what it seems obvious
&lt;/h1&gt;

&lt;p&gt;The first question that came to my mind as I was first reading about the OCP was: how can we make a system/module/functionality open for extensions but closed to modifications? And why should we do it?&lt;/p&gt;

&lt;p&gt;We can go from micro to macro in order to answer the question, so I will start with a classic: an oriented-object example. &lt;/p&gt;

&lt;p&gt;Let's think about a &lt;em&gt;chatbot&lt;/em&gt;, for instance. There's one simple basic and starter thing that it must be able to do that is: to talk. And, as for every conversation, a mean must be provided between the two parties so that they can listen to one another and understand each other. If our chatbot is built around the HowsEverything messenger platform, we might have something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Chatbot&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Answer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;{&lt;/span&gt; 
      &lt;span class="c1"&gt;// Some specific implementation about to deal with the HowsEverything platform&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the above example, both a language and a channel are specified so that this conversation is stablished through the HowsEverything app. But imagine that someday in the future, my chatbot is required to expand to some other platforms like Letter or Nosekindle. As the logic is platform-specific, we would have to change its functionality in order to embrace this new requirement and, therefore, break the open-closed principle. But that's not what we want.&lt;/p&gt;

&lt;p&gt;We can take a further step and make our chatbot platform-agnostic, so that it can be extensible to which platform it may arise as a new requirement. One possibility to do so is to introduce some abstraction to our code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Chatbot&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="nf"&gt;Answer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HowsEverythingChatbot&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Answer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// specific implementation }&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NosekindleChatbot&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Answer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// specific implementation }&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Doing that, our user might be able to always communicate with our chatbot in despite of the chosen platform. And we are also able to expand our chatbot from being platform-specific to being platform-agnostic.&lt;/p&gt;

&lt;p&gt;Abstractions are a beautiful way to achieve the open-closed principle by code, but that was just an example of this principle from a code perspective for you to be familiar with it. Now let's jump to the architecture level.&lt;/p&gt;

&lt;h1&gt;
  
  
  Extensibility with an Event-Driven Architecture
&lt;/h1&gt;

&lt;p&gt;To think about design and architecture is a exercise that I encourage every developer to do. Whether to think about it up-front or embrace the evolutionary side of things (I know, both ways could and should work together, but there's still a lot of discussion about it). The fact is: a successful system will grow over time. If it will be to 10, 100, 1k, 10k or 100k users depends on its purpose. But it will grow, and you'll have to make sure that it's growing wealth. Therefore, one approach that I really like and to think about in large scale systems is an &lt;em&gt;event-driven architecture&lt;/em&gt;. And the first things that I like to start thinking when I have to decided whether or not to follow this approach is to learn about my requirements and see if they fit as a rich domain with its &lt;strong&gt;commands&lt;/strong&gt; and &lt;strong&gt;events&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We can think about those like this: every action has a consequence. We can thrive this axiom to the fact the every user action within a system has a result. Improving the language: &lt;strong&gt;every successful command generates an event&lt;/strong&gt;. An UserSignUpCommand, where a new user is created, can be successfully stated as an UserSignedUpEvent. Note this event is an &lt;em&gt;confirmation that an intention has occurred in a correct manner&lt;/em&gt;. And what does the commander do with that information? It simply tells someone that it is there, i.e., &lt;strong&gt;a command raises an event&lt;/strong&gt; so that interested parties may listen to this event and do whatever they'd like to do with that piece of knowledge.&lt;/p&gt;

&lt;p&gt;Well, now imagine that the first requirement about the above example was simple: &lt;em&gt;"we must notify the user that he his registration was successful"&lt;/em&gt;. So after a command has been processed, we listen to an event and &lt;em&gt;handle&lt;/em&gt; it so that, in this handle, we send an email notification. Looks quite reactive, and it is, but quite simple still, right? &lt;/p&gt;

&lt;p&gt;Now imagine that some more things happen:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The marketing people should know about a new customers so they can start to track them in a customer funnel.&lt;/li&gt;
&lt;li&gt;The billing people should know about new customers, so that they can give him a free gift, like a 1-month subscription voucher.&lt;/li&gt;
&lt;li&gt;And so on ...&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And now is where this kind of approach shines: &lt;strong&gt;in an event-driven architecture we can have as many stakeholders as needed for a single event&lt;/strong&gt;. That means, that each new part that desires to do a new thing with this information must simply &lt;strong&gt;subscribe&lt;/strong&gt; to an event, in order to &lt;strong&gt;handle&lt;/strong&gt; it. And by doing so, we do not change a line, neither in our command nor in our first handler. Congratulations: you've just extended your system without moving a single character of code of one existing and working functionality.&lt;/p&gt;

&lt;p&gt;But, how can we after a successful command, notify other parties about an event? Well, one approach is to follow the &lt;strong&gt;pub/sub&lt;/strong&gt; pattern, where the application must simply &lt;strong&gt;publish&lt;/strong&gt; this event to someone who's responsible to handle it to the interested parties, so that these events are correctly delivered and handled by these parties. It can be done in a bunch of different ways, but before deciding &lt;em&gt;how&lt;/em&gt; we must decide &lt;em&gt;when&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Synchronously, with an in-memory &lt;a href="https://refactoring.guru/design-patterns/mediator"&gt;mediator&lt;/a&gt;. &lt;/li&gt;
&lt;li&gt;Asynchronously, with an &lt;a href="https://dzone.com/articles/design-patterns-event-bus"&gt;event-bus&lt;/a&gt; built around a &lt;a href="https://www.ibm.com/cloud/learn/message-brokers"&gt;message broker&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And there's a lot of room to talk about this kind of coupling (don't fool yourself, async processes are still coupled, but to time instead of space). But that's not the goal of this post.&lt;/p&gt;

&lt;p&gt;Finally, with this approach, we accomplish exact what the open-closed principle states: we extend our system, enriching its behaviour, without modifying what's already there. And that's what this principle is about.&lt;/p&gt;

&lt;h1&gt;
  
  
  Going further with Domain-Driven Design
&lt;/h1&gt;

&lt;p&gt;Domain and event-driven systems share a lot of similarities and we can use both approaches to, not only better develop one specific domain, but also to communicate specific domain actions with N &lt;strong&gt;aggregate roots&lt;/strong&gt; in the same application. In case you want to go more in-depth, Microsoft has a &lt;a href="https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/domain-events-design-implementation"&gt;really good article&lt;/a&gt; with even more references about the theme.&lt;/p&gt;

&lt;p&gt;For instance, let's take a given &lt;strong&gt;aggregate root&lt;/strong&gt; such as &lt;em&gt;Order&lt;/em&gt; in an e-commerce system. A user can search goods, add them to cart and execute the checkout with a &lt;strong&gt;PlaceOrderCommand&lt;/strong&gt;. This command, by its turn raises an &lt;strong&gt;OrderCreatedEvent&lt;/strong&gt;. At last, this event might be handled by different subdomains to performs tasks related to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;payments&lt;/li&gt;
&lt;li&gt;warehouse, supply chain and logistics&lt;/li&gt;
&lt;li&gt;order tracking by the user&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As I first learned about this, my eyes shined and I thought that I was entering a whole new world. But of course, once that with great power comes great responsibility, one must also be aware that these approaches have a plenty of drawbacks, specially if the event distribution is made asynchronously. In such case, you'll probably have to dive into some patterns to deal with the distribution of events such as &lt;a href="https://microservices.io/patterns/data/transactional-outbox.html"&gt;outbox pattern&lt;/a&gt; and &lt;a href="https://microservices.io/patterns/data/event-sourcing.html"&gt;event sourcing&lt;/a&gt;. Beyond that, it is possible that you'll have to deal with &lt;a href="https://microservices.io/patterns/data/saga.html"&gt;distributed transactions and sagas&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Outcome
&lt;/h1&gt;

&lt;p&gt;The open-closed principle is one of the most important principles regarding the growth of a system. To achieve it through event-driven architectures looks like an almost perfect match, as it allows new functionalities to be added with no disruption of old ones as the domain expands. And by applying event-driven we can automatically apply the open-closed principle to the architectural level.&lt;/p&gt;

&lt;p&gt;However, one should be aware that this approach carries with it a lot of advanced requirements and complexities, so one should really outweigh the pros and cons in order to decide if it fits its use case.&lt;/p&gt;

&lt;p&gt;What do you think about this theme? Let me know in the comments!&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>design</category>
      <category>messaging</category>
      <category>braziliandevs</category>
    </item>
    <item>
      <title>Explorando System.Threading.Channels</title>
      <dc:creator>Mateus Viegas</dc:creator>
      <pubDate>Sun, 17 May 2020 20:57:26 +0000</pubDate>
      <link>https://forem.com/mviegas/explorando-system-threading-channels-5cno</link>
      <guid>https://forem.com/mviegas/explorando-system-threading-channels-5cno</guid>
      <description>&lt;h1&gt;
  
  
  &lt;em&gt;tl/dr&lt;/em&gt;
&lt;/h1&gt;

&lt;p&gt;Este post tem como objetivo ser uma explicação prática da API System.Threading.Channels e como ela pode ser útil para implementar comunicação entre Tasks seguindo padrões pub/sub. Foi inicialmente publicado no meu &lt;a href="https://mateuscviegas.net/2020/05/explorando-system.threading.channels/"&gt;blog 🚀&lt;/a&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  Produtores x Consumidores
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://devblogs.microsoft.com/dotnet/an-introduction-to-system-threading-channels/"&gt;Neste post&lt;/a&gt; do blog da Microsoft é levantada a motivação pra criação da lib System.Threading.Channels. São recorrentes, até mesmo no dia a dia, os cenários de se produzir algo por uma ou mais partes e que esse algo vai posteriormente ser consumido por uma ou mais outras partes. E ainda que a produção e o consumo sejam feito de maneiras independentes por cada uma dessas partes, ambas precisam estar conectadas uma(s) à(s) outra(s) para que isso aconteça. Por exemplo, uma encomenda enviada por um remetente, para ser entregue a um destinatário, precisa passar por todo um processo logístico até que isso aconteça. Esse processo pode ser abstraído como um &lt;em&gt;canal&lt;/em&gt; entre as duas partes interessadas, e esse canal que permite o recebimento.&lt;/p&gt;

&lt;p&gt;É justamente uma abstração dessa conexão, entitulada de &lt;strong&gt;channel&lt;/strong&gt; que é criada com a lib &lt;a href="https://www.nuget.org/packages/System.Threading.Channels"&gt;System.Threading.Channels&lt;/a&gt;. Para usá-la, basta instalar um package nuget, que é compatível com o .NET Standard(&amp;gt;= 1.3), .NET Core (&amp;gt;= 3.1) e até mesmo com o NET Framework (&amp;gt;= 4.6).&lt;/p&gt;




&lt;h1&gt;
  
  
  Dissecando um channel
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Abrindo channels
&lt;/h2&gt;

&lt;p&gt;Um &lt;strong&gt;channel&lt;/strong&gt; pode ser visto, portanto, como uma estrutura de dados básica pra estabelecer uma conexão entre produtores e consumidores. É uma estrutura genérica e que pode ser criada através da classe &lt;code&gt;System.Threading.Channels.Channel&amp;lt;T&amp;gt;&lt;/code&gt; pelos seguintes métodos, que são static factories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;CreateBounded&amp;lt;T&amp;gt;(int capacity)&lt;/code&gt;: cria um &lt;em&gt;bounded channel&lt;/em&gt;, que é um &lt;em&gt;canal&lt;/em&gt; que tem uma capacidade de objetos (mensagens) definida. Se um &lt;em&gt;channel&lt;/em&gt; é criado desta forma, significa que, uma vez que ele atingiu sua capacidade máxima, ele só poderá receber um novo objeto depois que outro objeto previamente colocado nele por um &lt;em&gt;writer&lt;/em&gt; seja consumido por um &lt;em&gt;reader&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Channel&amp;lt;T&amp;gt; CreateBounded&amp;lt;T&amp;gt;(BoundedChannelOptions options)&lt;/code&gt;: tem exatamente o mesmo comportamento da factory acima, com o adicional da possibilidade de definição de opções do canal. Na data de escrita deste post, essas opções setam não só a capacidade, mas também como o &lt;em&gt;channel&lt;/em&gt; vai se comportar no caso de ter chegado no topo de sua capacidade. Isso é definido através da propriedade &lt;code&gt;FullMode&lt;/code&gt;, um enumerado com quatro opções:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Wait&lt;/code&gt;: espera que o canal tenha espaço livre para completar uma operação de escrita.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DropNewest&lt;/code&gt;: descarta o item mais novo já escrito mas ainda não lido no canal, para abrir espaço para o que acabou de chegar.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DropOldest&lt;/code&gt;: de maneira semalhante à operação acima, porém com o item mais antigo já escrito mas ainda não lido no canal.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DropWrite&lt;/code&gt;: descarta outro item que esteja sendo escrito no canal.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Channel&amp;lt;T&amp;gt; CreateUnbounded&amp;lt;T&amp;gt;()&lt;/code&gt;: cria um &lt;em&gt;unbounded channel&lt;/em&gt; - um canal sem capacidade definida, aonde o céu (na verdade, a quantidade de memória RAM disponível) é o limite. Segundo testes de benchmark apresentados &lt;a href="https://ndportmann.com/system-threading-channels/"&gt;por este blog&lt;/a&gt;, &lt;em&gt;unbounded channels&lt;/em&gt; são mais performáticos. Contudo, criar canais dessa forma pode ser perigoso uma vez que eles não tem limitação e podem consumir toda a memória disponível. Por esta razão, é dito que eles são menos seguros que os seus irmãos apresentados anteriormente. Deve ser analisado o tradeoff de segurança x performance, caso o nível de requisitos seja crítico a este ponto. Caso seja possível garantir a capacidade máxima de maneira externa, pode valer o risco.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Channel&amp;lt;T&amp;gt; CreateUnbounded&amp;lt;T&amp;gt;(UnboundedChannelOptions options)&lt;/code&gt;: tem exatamente o mesmo comportamento da factory acima, com o adicional de definição de opções do canal. E esta classe tem uma propriedade que é bem interessante:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;AllowSynchronousContinuations&lt;/code&gt;: de acordo com a &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.threading.channels.channeloptions.allowsynchronouscontinuations?view=netcore-3.1#System_Threading_Channels_ChannelOptions_AllowSynchronousContinuations"&gt;doc oficial&lt;/a&gt;, essa propriedade tem uma comportamento bem interessante. Ela permite, de certaforma, que um &lt;em&gt;produtor&lt;/em&gt; vire, temporariamente, um &lt;em&gt;consumidor&lt;/em&gt;. Como? Vamos entrar nesse detalhe mais abaixo após entender como produtores (&lt;em&gt;writers&lt;/em&gt;) e consumidores (&lt;em&gt;readers&lt;/em&gt;) se comportam.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ambas as classes de opções de &lt;em&gt;unbounded&lt;/em&gt; e &lt;em&gt;bounded channels&lt;/em&gt; herdam de &lt;code&gt;ChannelOptions&lt;/code&gt; que, por sua vez, possui duas propriedades:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;SingleWriter&lt;/code&gt;: tem como default false. Se setada como true, é garantida que acontecerá apenas uma operação de escrita por vez. Por padrão, não existe essa constraint, e a própria estrutura da api de channels pode otimizar algumas operações de escrita internamente.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SingleReader&lt;/code&gt;: o mesmo comportamento da operação acima, porém com operações de leitura no canal.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No exemplo abaixo, criamos um &lt;em&gt;bounded channel&lt;/em&gt; que receberá objetos do tipo &lt;code&gt;int&lt;/code&gt; com capacidade máxima de 1.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Threading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Channels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateBounded&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;BoundedChannelOptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;FullMode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BoundedChannelFullMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wait&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Encerrando channels
&lt;/h2&gt;

&lt;p&gt;Um canal pode ser encerrado através de um recurso chamado &lt;em&gt;completion&lt;/em&gt;. Este recurso é controlado sempre pelos produtores (&lt;em&gt;writers&lt;/em&gt;) e pode ser ativado através dos métodos &lt;code&gt;Complete&lt;/code&gt; e &lt;code&gt;TryComplete&lt;/code&gt;, que podem inclusive receber uma exceção para indicar que o &lt;em&gt;channel&lt;/em&gt; foi encerrado devido à um erro.&lt;/p&gt;

&lt;p&gt;Durante uma operação de leitura, os consumidores (&lt;em&gt;readers&lt;/em&gt;) podem, por sua vez, verificar se um canal foi encerrado chamando &lt;code&gt;channel.Completion.IsCompleted&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Produzindo e consumindo mensagens
&lt;/h2&gt;

&lt;p&gt;Mensagens podem ser produzidas no canal através de um &lt;code&gt;Writer&lt;/code&gt; e lidas por um &lt;code&gt;Reader&lt;/code&gt;, propriedades da classe &lt;code&gt;Channel&amp;lt;T&amp;gt;&lt;/code&gt;. Isso pode através dos seguintes métodos:&lt;/p&gt;

&lt;p&gt;1) &lt;code&gt;TryWrite/TryRead&lt;/code&gt;: tentam escrever/ler uma mensagem de maneira síncrona no canal. Caso não seja possível, pelas opções definidias, a mensagem é descartada e o método retorna &lt;code&gt;false&lt;/code&gt;. Caso contrário, retorna &lt;code&gt;true&lt;/code&gt;. No exemplo abaixo, escrevemos no console se uma mensagem não pôde ser escrita no canal. Isso ficará mais claro no exemplo inteiro que daremos um pouco mais à frente, aonde colocamos um delay entre a leitura e a escrita pra simular cenários em que o canal esteja funcionando na capacidade total e, por consequência e a depender de como foi configurado, esteja impedido de receber novas escritas de mensagens.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Dropping &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;2) &lt;code&gt;WaitToWriteAsync/WaitToReadAsync&lt;/code&gt;: retornam uma &lt;code&gt;ValueTask&amp;lt;bool&amp;gt;&lt;/code&gt; e indicam se o canal está disponível para escrever/ler mensagens, baseados nas opções e capacidade definidas. Por padrão, estes métodos não dispararão uma exceção caso o canal já esteja encerrado, a não ser que uma exceção seja passada por parâmetro nos métodos &lt;code&gt;Complete&lt;/code&gt; e &lt;code&gt;TryComplete&lt;/code&gt;, vistos acima. No exemplo do código abaixo, o consumidor (&lt;em&gt;reader&lt;/em&gt;) permanece ativo enquanto o loop for verdadeiro, e isso acontecerá indefinidamente a não ser que o canal seja encerrado. Enquanto o canal não for encerrado, mas também não chegarem mensagens, ele ficará inativo. A implementação conjunta com o TryRead é interessante pelo seguinte fato: num cenário onde múltiplos consumidores competem por uma mesma mensagem, e a produção dessas mensagens é feita de forma aleatória, a mensagem que foi sinalizada como disponível para todos os consumidores pode ser consumida mais rapidamente  por um outro consumidor concorrente.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WaitToReadAsync&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryRead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;                    
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Message already &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; consumed"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;3) &lt;code&gt;WriteAsync/ReadAsync&lt;/code&gt;: são a implementação assíncrona dos métodos &lt;code&gt;TryRead&lt;/code&gt;/&lt;code&gt;TryWrite&lt;/code&gt;, com um importante adendo de que ambos disparam uma exceção do tipo &lt;code&gt;ChannelClosedException&lt;/code&gt; se o canal já tiver sido encerrado por um &lt;em&gt;writer&lt;/em&gt;. Para se evitar essa situação, é preferível usar os métodos &lt;code&gt;WaitTo&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;ReadAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Channel&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Readed &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ConfigureAwait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// An exception will be thrown when the channel is closed&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Consumindo todas as mensagens de uma vez
&lt;/h3&gt;

&lt;p&gt;Além dos pares de métodos acima, temos ainda o &lt;code&gt;ReadAllAsync&lt;/code&gt; que cria um &lt;code&gt;IAsyncEnumerable&lt;/code&gt; de todos os dados disponíveis para leitura no canal e nos permite iterar de maneira assíncrona sobre eles.&lt;/p&gt;

&lt;h3&gt;
  
  
  Voltando ao AllowSynchronousContinuations
&lt;/h3&gt;

&lt;p&gt;Como dito anteriormente, a propriedade &lt;code&gt;AllowSynchronousContinuations&lt;/code&gt; permite com que um produtor vire temporariamente um consumidor. Vamos pensar no seguinte exemplo: um consumidor chama uma operação de leitura num canal sem mensagens, internamente esse canal cria algo como um callback que será chamado quando alguma mensagem for escrita nele e, por default, isso é feito de maneira assíncrona enfileirando a invocação desse callback para ser executada em uma thread diferente da thread do produtor. &lt;/p&gt;

&lt;p&gt;Quando setamos essa propriedade como &lt;code&gt;true&lt;/code&gt;, estamos dizendo ao canal que esse callback pode ser feito de maneira síncrona, ou seja, a mesma thread que escreveu a mensagem irá consumí-la. Isso pode ser uma vantagem em termos de performance, mas deve ser usada com cuidado em alguns cenários. Por exemplo, se algum tipo de &lt;code&gt;lock&lt;/code&gt; estiver sendo usado na escrita, a chamada do callback de leitura pode ocorrer com esse lock ativo, o que pode gerar comportamentos não-desejados no seu código.&lt;/p&gt;




&lt;h1&gt;
  
  
  Exemplos
&lt;/h1&gt;

&lt;p&gt;Os exemplos abaixo podem ser encontrados &lt;a href="https://github.com/mviegas/ChannelsDemo"&gt;neste repo&lt;/a&gt;. Nele temos implementações básicas de um produtor e um consumidor interagindo através de um &lt;em&gt;channel&lt;/em&gt; de maneira assíncrona e não-bloqueante.&lt;/p&gt;

&lt;h2&gt;
  
  
  Escrevendo num canal com a capacidade máxima
&lt;/h2&gt;

&lt;p&gt;No exemplo abaixo, setamos velocidades diferentes de leitura e escrita para que a escrita tente acontecer em momentos em que o canal estiver em sua capacidade máxima.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;ChannelOutOfCapacityExample&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Setting a read delay bigger than a wrote delay, so that we can see what happens when channels are "full"&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;readDelay&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;500&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;writeDelay&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Creating a bounded channel with capacity of 1 &lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateBounded&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;BoundedChannelOptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Setting this property we say that when the channel is full and another item is dispatched to it, it should wait until the current item is processed to process the next&lt;/span&gt;
        &lt;span class="n"&gt;FullMode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BoundedChannelFullMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wait&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// Calling Task.Run so that the Channel.Writer executes in a different synchronization context than the Channel.Reader&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;ExtendedConsole&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Dropping &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ConsoleColor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Red&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;writeDelay&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ConfigureAwait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadAsync&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;ConfigureAwait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;ExtendedConsole&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Readed &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ConsoleColor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Green&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;readDelay&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ConfigureAwait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Encerrando um canal sem exceções pelo consumidor
&lt;/h2&gt;

&lt;p&gt;No exemplo abaixo exemplificamos o uso do WaitToReadAsync para mostrar como exceções podem ser evitadas no &lt;em&gt;completion&lt;/em&gt; do canal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;ChannelCompletedWithoutExceptionRaised&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateBounded&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;BoundedChannelOptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;FullMode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BoundedChannelFullMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wait&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;ExtendedConsole&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Writing &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ConsoleColor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Blue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;ExtendedConsole&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Writer: completing channel after 10 executions"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ConsoleColor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Yellow&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryComplete&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// Using WaitToRead, no exception is raised when channel is completed, unless it is explicit passed on completion&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WaitToReadAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ConfigureAwait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryRead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;ExtendedConsole&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Readed &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ConsoleColor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Green&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Message already &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; consumed"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;






&lt;h2&gt;
  
  
  Consumidores concorrentes
&lt;/h2&gt;

&lt;p&gt;No exemplo abaixo, temos um canal com um produtor e três consumidores concorrentes. Dessa forma, quando um consumidor é ativado pelo &lt;code&gt;WaitToReadAsync&lt;/code&gt;, por existirem outros consumidores para o mesmo canal, a mensagem que ativou o método já pode ter sido consumida por outro concorrente, o que faria o &lt;code&gt;TryRead&lt;/code&gt; retornar false.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;ChannelWithCompetingConsumers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateBounded&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;BoundedChannelOptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;FullMode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BoundedChannelFullMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wait&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;ExtendedConsole&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Writing &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ConsoleColor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Blue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;ExtendedConsole&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Writer: completing channel after 10 executions"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ConsoleColor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Yellow&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryComplete&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;firstConsumer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Consumer&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;secondConsumer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Consumer&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;thirdConsumer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Consumer&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WhenAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;firstConsumer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConsumeAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;secondConsumer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConsumeAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;thirdConsumer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConsumeAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;ConfigureAwait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Consumer&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;ChannelReader&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_reader&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;Random&lt;/span&gt; &lt;span class="n"&gt;_random&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Random&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Consumer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChannelReader&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NewGuid&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;_reader&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;ConsumeAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Using WaitToRead, no exception is raised when channel is completed, unless it is explicit passed on completion&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WaitToReadAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryRead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                &lt;span class="n"&gt;ExtendedConsole&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"ID &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; === Readed &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ConsoleColor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Green&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;
                &lt;span class="n"&gt;ExtendedConsole&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"ID &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; === Consumer awoken but message already consumed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ConsoleColor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Yellow&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;500&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Conclusão
&lt;/h1&gt;

&lt;p&gt;Como visto, &lt;strong&gt;channels&lt;/strong&gt; são abstrações bem poderosas pra mecanismos de pub/sub de maneira assíncrona e não-bloqueante com aplicações .NET (Core e Framework). Sua implementação tem como foco trabalhar em cenários concorrentes com excelentes performance e flexibilidade e são um recurso bem interessante, principalmente pra processamentos feitos de maneira assíncrona através da comunicação entre várias &lt;em&gt;tasks&lt;/em&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  Referências
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Working with Channels in .NET: &lt;a href="https://www.youtube.com/watch?v=gT06qvQLtJ0"&gt;https://www.youtube.com/watch?v=gT06qvQLtJ0&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An Introduction to System.Threading.Channels: &lt;a href="https://devblogs.microsoft.com/dotnet/an-introduction-to-system-threading-channels/"&gt;https://devblogs.microsoft.com/dotnet/an-introduction-to-system-threading-channels/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An Introduction to System.Threading.Channels (mesmo título, outro post): &lt;a href="https://www.stevejgordon.co.uk/an-introduction-to-system-threading-channels"&gt;https://www.stevejgordon.co.uk/an-introduction-to-system-threading-channels&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Exploring System.Threading.Channels: &lt;a href="https://ndportmann.com/system-threading-channels/"&gt;https://ndportmann.com/system-threading-channels/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>dotnet</category>
      <category>pubsub</category>
      <category>csharp</category>
      <category>braziliandevs</category>
    </item>
    <item>
      <title>(pt-BR) Introdução ao RabbitMQ com .NET Core</title>
      <dc:creator>Mateus Viegas</dc:creator>
      <pubDate>Mon, 16 Dec 2019 11:49:07 +0000</pubDate>
      <link>https://forem.com/mviegas/pt-br-introducao-ao-rabbitmq-com-net-core-15oc</link>
      <guid>https://forem.com/mviegas/pt-br-introducao-ao-rabbitmq-com-net-core-15oc</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;tl/dr:&lt;/em&gt; preparei aqui um guia introdutório a partir de várias leituras e vídeos que escutei ao longo desse ano (fontes serão devidamente dadas) explicando o básico sobre o RabbitMQ e como ele pode ser um recurso interessante na infra-estrutura pra desacoplamento e comunicação entre aplicações. Meu objetivo aqui é ser mais coeso e objetivo e apresentar uma visão básica, porém suficiente pra um entendimento incial, e em português. Caso você saiba inglês, colocarei também alguns links ao longo do artigo.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  RabbitMQ: conceitos básicos e motivação
&lt;/h2&gt;

&lt;p&gt;Atualmente, muito se fala do RabbitMQ e message brokers como ferramentas para quebrar os "monolitos" - e aqui eu falo sem o pejorativismo que essa palavra carrega ultimamente. A distribuição de um monolito e o surgimento de arquiteturas distribuídas podem trazer vantagens como desacoplamento, maior coesão e autonomia das partes desacopladas. Essa nova arquitetura distribuída passa a se basear na comunicação entre os participantes para realizar certas ações, o que traz algumas outras complexidades. É introduzida uma camada extra, a rede, e por isso garantias de resiliência, confiabilidade e escalabilidade passam a ser ainda mais necessárias pra esse novo modo de comunicação.&lt;/p&gt;

&lt;p&gt;Dito isso, o que é o RabbitMQ? É um &lt;strong&gt;message broker&lt;/strong&gt;, um recurso que se baseia no conceito de mensageria e que funciona da seguinte forma: uma determinada aplicação &lt;em&gt;publica&lt;/em&gt; uma determinada mensagem para o &lt;em&gt;broker&lt;/em&gt; que recebe essa mensagem e a encaminha para uma &lt;em&gt;fila&lt;/em&gt;. Na outra ponta, uma outra aplicação se &lt;em&gt;inscreve&lt;/em&gt; para receber as mensagens daquela fila. Temos então alguém que publica (&lt;em&gt;publisher&lt;/em&gt;), alguém que se inscreve pra ouvir as mensagens publicadas (&lt;em&gt;subscriber&lt;/em&gt;) e um agente no meio que distribui e entrega essas mensagens (&lt;em&gt;message broker&lt;/em&gt;). É o padrão &lt;em&gt;pub/sub&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;O RabbitMQ traz suporte à alguns protocolos diferentes, como AMQP, MQTT e STOMP. Meu objetivo aqui é ser mais introdutório, mas o Luiz Carlos Faria fala um pouco mais à fundo sobre isso &lt;a href="https://www.youtube.com/watch?v=iEeJDAU-Sg0"&gt;nesse vídeo&lt;/a&gt; e numa série de posts que começa &lt;a href="https://gago.io/blog/rabbitmq-amqp-1-prefacio/"&gt;com esse aqui&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vantag ... ou melhor, algumas considerações
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Escalabilidade&lt;/strong&gt;: esse tipo de infra-estrutura suporta centenas de milhares produtos/consumidores de forma simultânea e possui a &lt;strong&gt;entrega única&lt;/strong&gt; como característica, ou seja, cada mensagem só entregue à um consumidor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mediação&lt;/strong&gt;: uma mesma mensagem talvez precise ser entrege para &lt;em&gt;n&lt;/em&gt; consumidores que irão processá-la de maneira diferente. O Rabbit possui mecanismos para roteamento e distribuição dessa mensagem, atuando como um &lt;em&gt;mediador&lt;/em&gt; dentro da camada de transporte dessa arquitetura distribuída.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Assincronicidade&lt;/strong&gt;: o envio de mensagens assíncronas retira um ponto de falha de quem envia essas mensagens, o que deixa a aplicação que publica uma mensagem mais leve, pois desacoplou uma responsabilidade dela. Isso contudo, introduz outros possíveis pontos de falha que devem ser tratados para garantir uma aplicação &lt;em&gt;resiliente&lt;/em&gt;. Por exemplo, ao retirar o salvamento de log de uma transação SQL dentro da sua aplicação e passando a publicar esse log num message broker pra ser consumido por outra ponta, você retira a dependência dessa transação mas inclui novos possíveis pontos de falha como, por exemplo, a rede que passa a ser uma camada de comunicação e o cliente que vai consumir as mensagens. Em um desses pontos conseguimos ter razoável controle quando publicamos, no outro não. Existem técnicas pra lidar com isso, mas não é o objetivo desse post.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Como funciona
&lt;/h2&gt;

&lt;p&gt;Uma aplicação &lt;em&gt;publica&lt;/em&gt; uma mensagem para o Rabbit. Essa mensagem então é enviada para uma &lt;strong&gt;exchange&lt;/strong&gt;, que é um artefato de roteamento, fazendo uma analogia, como um &lt;em&gt;carteiro responsável por fazer a entrega&lt;/em&gt;). As exchanges, cada qual de acordo com sua configuração, direcionam a mensagem para uma ou mais &lt;strong&gt;filas&lt;/strong&gt;. Na outra ponta, existe um (ou mais) &lt;strong&gt;consumidor(es)&lt;/strong&gt; responsável por escutar a fila e consumir a mensagem (mais sobre isso abaixo).&lt;/p&gt;

&lt;p&gt;É importante dizer que se uma mensagem chegar numa fila com 3 consumidores conectados, &lt;strong&gt;apenas um deles receberá a mensagem para processamento&lt;/strong&gt; (entrega única). Caso seja necessário que mais de um consumidor receba a mesma mensagem, , a exchange para qual a mensagem é enviada deve ser configurada para rotear essa mensagem para várias filas. Assim, a mensagem é replicada e entregue para n filas, permitindo consumidores independentes de uma mesma mensagem - &lt;em&gt;spoiler do que vamos falar mais à frente&lt;/em&gt;. Aqui embaixo uma imagem do CloudAMQP para ilustrar:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qlpwbHbv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.cloudamqp.com/img/docs/camqp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qlpwbHbv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.cloudamqp.com/img/docs/camqp.png" alt="Imagem do CloudAQMP"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;O CloudAMQP (um provider de Rabbit na nuvem) tem uma série muito boa (em inglês) de RabbitMQ para iniciantes. Disponível &lt;a href="https://www.cloudamqp.com/blog/2015-05-18-part1-rabbitmq-for-beginners-what-is-rabbitmq.html"&gt;nesse link aqui&lt;/a&gt;. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Quem faz o que dentro do RabbitMQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Exchange
&lt;/h3&gt;

&lt;p&gt;Sendo um pouco repetitivo, a Exchange é um artefato de roteamento que funciona como um carteiro responsável por entregar as mensagens. Quando uma mensagem é publicada numa exchange, é enviada uma propriedade (setada por quem envia) chamada &lt;em&gt;routing key&lt;/em&gt;. Essa key funciona como o endereço do destinatário. A exchange olha a key e sabe para onde entregar. &lt;/p&gt;

&lt;p&gt;Dito isso, Existem quatro tipos exchange no RabbitMQ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Direct&lt;/em&gt;: a mensagem é enviada para uma fila com o mesmo nome da routing key. Se a routing key não for informada, ela é enviada para uma fila padrão.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Fanout&lt;/em&gt;: a mensagem é distribuída para todas as filas associadas (falaremos sobre isso mais abaixo). Esse tipo de exchange ignora a routing key.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Topic&lt;/em&gt;: a mensagem é distribuída de acordo com um padrão enviado pela routing key.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Header&lt;/em&gt;: a mensagem é distribuída de acordo com seus cabeçalhos. Dessa forma, é feito um match com qual consumidor deve receber aquela mensagem.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Queues (filas)
&lt;/h3&gt;

&lt;p&gt;Recebem as mensagens da exchange e armazenam até que um consumidor se conecte para retirar as mensagens de lá. O nome sugere, isso é feito seguindo uma lógica FIFO (first-in, first-out). Podem ter os seguintes atributos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Durable&lt;/em&gt;: a fila sobrevive ao restart do message broker. O RabbitMQ possui um banco de dados chamado &lt;em&gt;Mnesia&lt;/em&gt; aonde armazena essas informações.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Exclusive&lt;/em&gt;: possui somente 1 consumidor e morre quando não há mais consumidores.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Autodelete&lt;/em&gt;: morre quando não há mais mensagens.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Binds (associações)
&lt;/h3&gt;

&lt;p&gt;Para que uma exchange entregue uma mensagem para uma fila, deve haver uma associação, um &lt;strong&gt;bind&lt;/strong&gt; entre elas. Isso pode ser feito de maneira programática por quem envia ou através de uma interface web que o RabbitMQ disponibiliza para gerenciamento do broker.&lt;/p&gt;

&lt;h3&gt;
  
  
  Virtual hosts (vhosts)
&lt;/h3&gt;

&lt;p&gt;Tudo isso que falamos acima, são entidades do RabbitMQ. Um grupo lógico dessas entidades é chamado de &lt;strong&gt;virtual host&lt;/strong&gt;. Um vhost funciona como um &lt;em&gt;tenant&lt;/em&gt; dentro do RabbitMQ, que, inclusive, é descrito (na doc sobre vhosts)[&lt;a href="https://www.rabbitmq.com/vhosts.html"&gt;https://www.rabbitmq.com/vhosts.html&lt;/a&gt;] por essa razão um sistema multi-tenant.&lt;/p&gt;

&lt;p&gt;É importante frisar que um vhost é um separação &lt;em&gt;lógica&lt;/em&gt; e não física dessas entidades. Separar esses recursos fisicamente é detalhe de implementação de infra-estrutura.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fire and forget 🤘🏼
&lt;/h2&gt;

&lt;p&gt;Uma das premissas básicas desse tipo de recurso é que quem publica não conhecem quem consome. Quando uma mensagem é disparada, ela é entregue ao mediador e quem disparou não sabe mais sobre o seu paradeiro. Conseguimos saber apenas se ela chegou ao mediador. Por isso, sempre que algum tipo de retorno for necessário, é seguro dizer que o RabbitMQ não é o recurso adequado para ser utilizado. &lt;/p&gt;

&lt;p&gt;Por outro lado, existem alguns lugares aonde podemos ter ganhos consideráveis com esse padrão:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Quando não me importa o retorno da mensagem.&lt;/li&gt;
&lt;li&gt;Quando n workers precisam processar uma única mensagem, por exemplo, uma api REST que recebe uma requisição e distribui ela para processamento paralelo.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Quando um consumidor recebe uma mensagem, ele é responsável por dizer ao broker que essa mensagem foi consumida e que já pode ser retirada da fila. É o conceito de &lt;strong&gt;acknowledgement&lt;/strong&gt;. O consumidor é responsável por emitir um &lt;em&gt;ack&lt;/em&gt; (mais simpático, mais curto). Ao receber o ack, o Rabbit entende que o consumidor disse: &lt;em&gt;ok Rabbit, já peguei e processei a mensagem, pode retirar ela da fila&lt;/em&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Padrões de consumo
&lt;/h2&gt;

&lt;p&gt;Existem diversos padrões de consumo disponíveis, mas não é meu objetivo falar mais sobre eles nesse post. O &lt;strong&gt;RPC&lt;/strong&gt; é um deles e o próprio site de docs do RabbitMQ tem um tutorial disponível &lt;a href="https://www.rabbitmq.com/tutorials/tutorial-six-dotnet.html"&gt;aqui&lt;/a&gt;. Eu, contudo, recomendo que os outros tutoriais sejam feitos antes pra exercitar.&lt;/p&gt;

&lt;h2&gt;
  
  
  E agora, como eu testo isso tudo?!
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Provisionando
&lt;/h3&gt;

&lt;p&gt;De maneira rápida, existem duas maneiras que eu recomendo pra se começar a utilizar o RabbitMQ para aprender desenvolvendo.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.cloudamqp.com/plans.html"&gt;Conta free no CloudAQMP&lt;/a&gt;. Importante dizer que esse post não é um ads pra eles, embora eu já os tenha citado algumas vezes. É só porque eles tem um vasto conteúdo pra iniciante e permitem uma conta free. A desvantagem da conta free é que ela funciona dentro de uma infra-estrutura compartilhada do RabbitMQ, como um &lt;strong&gt;virtual host&lt;/strong&gt; (um assunto-futuro, quem sabe).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Subindo um container no Docker&lt;/strong&gt;. Eu costumo ter isso nos meus &lt;em&gt;docker-compose.override.yml&lt;/em&gt;, mas um comando para subir de primeira é esse aqui:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;docker run -d --hostname my-rabbit --name some-rabbit -p 5672:5672 15672:15672 rabbitmq:3-management&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;O usuário e senha padrão para conexão e acesso da GUI são guest/guest.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Utilizando o RabbitMQ com .NET Core
&lt;/h4&gt;

&lt;p&gt;Existem uma série de bibliotecas que implementam com boas práticas um &lt;em&gt;service bus&lt;/em&gt; e trabalham algumas garantias como resiliência para falhas na conexão com o broker, mas não é o objetivo mostrá-las. Pra esse exemplo, basta criar duas aplicações console em .NET Core a adicionar a cada uma o package RabbitMQ.Client pelo seguinte comando:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dotnet add package RabbitMQ.Client&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;em&gt;Publisher&lt;/em&gt;: console app em .NET Core
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Importante&lt;/strong&gt;: nos dois códigos abaixo vocês vão ver que eu não especifiquei o &lt;em&gt;vhost&lt;/em&gt; na conexão. Quando isso acontece, é criada uma conexão ao vhost padrão &lt;em&gt;/&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;RabbitMQ.Client&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;RabbitMQDemo.Publisher&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Program&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;connectionFactory&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ConnectionFactory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;HostName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"localhost"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;Port&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;5672&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;UserName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"guest"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;Password&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"guest"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;};&lt;/span&gt;

            &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connectionFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateConnection&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateModel&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Type your message"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;teste&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadLine&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

                    &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;QueueDeclare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"tests"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;durable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;exclusive&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;autoDelete&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
                        &lt;span class="s"&gt;$"&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"dd/MM/yyyy HH:mm:ss"&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s"&gt; - "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
                        &lt;span class="s"&gt;$"Message content: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;teste&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Encoding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UTF8&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                    &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;BasicPublish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exchange&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                         &lt;span class="n"&gt;routingKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"tests"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                         &lt;span class="n"&gt;basicProperties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                         &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;em&gt;Consumer&lt;/em&gt;: console app .NET Core
&lt;/h4&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;RabbitMQ.Client&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;RabbitMQ.Client.Events&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;RabbitMQDemo.Consumer&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Program&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;connectionFactory&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ConnectionFactory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;HostName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"localhost"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;Port&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;5672&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;UserName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"guest"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;Password&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"guest"&lt;/span&gt;
            &lt;span class="p"&gt;};&lt;/span&gt;

            &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connectionFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateConnection&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateModel&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;QueueDeclare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"tests"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;durable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;exclusive&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;autoDelete&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;consumer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;EventingBasicConsumer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                &lt;span class="n"&gt;consumer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Received&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;eventArgs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Encoding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UTF8&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eventArgs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewLine&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"[New message received] "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="p"&gt;};&lt;/span&gt;

                &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;BasicConsume&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"tests"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                     &lt;span class="n"&gt;autoAck&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                     &lt;span class="n"&gt;consumer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;consumer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Waiting messages to proccess"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Press some key to exit..."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadKey&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  Output das aplicações de exemplo
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qdoyklu_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/vfzm9liv2eaphgk04656.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qdoyklu_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/vfzm9liv2eaphgk04656.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9IMpN7CB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/24khmzhn9dtceboblka0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9IMpN7CB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/24khmzhn9dtceboblka0.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Resumo
&lt;/h2&gt;

&lt;p&gt;O objetivo desse post foi dar um overview básico e o caminho das pedras pra quem quiser se aventurar nesse mundo de sistemas distribuídos com brokers de mensageria. Existem uma série de outras preocupações que esse tipo de arquitetura trazem como: o message broker passa a ser uma parte vital de sua infraestrutura, então ele precisa ter &lt;em&gt;disponibilidade&lt;/em&gt; na última casa decimal dos 99,99999....%.&lt;/p&gt;

&lt;p&gt;Por fim, gostaria de lembrar que &lt;strong&gt;não existem balas de prata&lt;/strong&gt;. Por isso, pense com cuidado e avalie se cabe na sua aplicação. O RabbitMQ é um recurso incrível, assim como são arquiteturas distribuídas, mas que pode(m) trazer sérias dores de cabeça e prejuízos para o negócio se aplicados sem necessidade e/ou de forma errada.&lt;/p&gt;

&lt;h3&gt;
  
  
  Links úteis:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.rabbitmq.com/#getstarted"&gt;Documentação oficial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gago.io/blog/rabbitmq-amqp-1-prefacio/"&gt;Série do Luiz Carlos Faria sobre RabbitMQ e AMQP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.cloudamqp.com/blog/2015-05-18-part1-rabbitmq-for-beginners-what-is-rabbitmq.html"&gt;(en) Série do CloudAMQP RabbitMQ para iniciantes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>dotnet</category>
      <category>rabbitmq</category>
      <category>distributedsystems</category>
      <category>microservices</category>
    </item>
  </channel>
</rss>
