<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Fabrizio Messina, Author at PythonRight</title>
	<atom:link href="https://pythonright.com/author/fabriziomessina/feed/" rel="self" type="application/rss+xml" />
	<link>https://pythonright.com/author/fabriziomessina/</link>
	<description>Clean code is written by those who care.</description>
	<lastBuildDate>Wed, 25 Sep 2019 08:44:00 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.3.2</generator>

<image>
	<url>https://pythonright.com/wp-content/uploads/2018/11/python-right-logo-150x150.png</url>
	<title>Fabrizio Messina, Author at PythonRight</title>
	<link>https://pythonright.com/author/fabriziomessina/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Celery: Advanced Routing Techniques</title>
		<link>https://pythonright.com/celery-advanced-routing-techniques/</link>
					<comments>https://pythonright.com/celery-advanced-routing-techniques/#respond</comments>
		
		<dc:creator><![CDATA[Fabrizio Messina]]></dc:creator>
		<pubDate>Wed, 25 Sep 2019 08:38:22 +0000</pubDate>
				<category><![CDATA[Python 3]]></category>
		<guid isPermaLink="false">https://pythonright.com/?p=176</guid>

					<description><![CDATA[<p>Nowadays the microservice architecture is considered the most scalable approach for a wide range of business problems, in particular because it promises fast and lean development cycles. The best case scenario for microservices is when the data entities that define our applications are completely decoupled. Unfortunately that is rarely the case, and managing the communication &#8230; <a href="https://pythonright.com/celery-advanced-routing-techniques/" class="more-link">Continue reading <span class="screen-reader-text">Celery: Advanced Routing Techniques</span></a></p>
<p>The post <a rel="nofollow" href="https://pythonright.com/celery-advanced-routing-techniques/">Celery: Advanced Routing Techniques</a> appeared first on <a rel="nofollow" href="https://pythonright.com">PythonRight</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Nowadays the microservice architecture is considered the most scalable approach for a wide range of business problems, in particular because it promises fast and lean development cycles.</p>



<p>The best case scenario for microservices is when the data entities that define our applications are completely decoupled. Unfortunately that is rarely the case, and managing the <a href="https://docs.microsoft.com/en-us/dotnet/standard/microservices-architecture/architect-microservice-container-applications/communication-in-microservice-architecture">communication between microservices</a> is far from the easiest task a team may encounter.</p>



<p>In the most simple use case, we can use plain <strong>HTTPS</strong> requests to send and receive messages from and to other services.</p>



<p>Unfortunately this methodology does in fact tend to couple the microservices and depending on scale, could deteriorate the performance of the application.</p>



<p></p>



<blockquote class="wp-block-quote" style="font-size:90%;font-style:normal">
<p><strong style="font-size:110%;font-weight:1000"> 
Use case: A simple ecommerce
</strong></p>

<p>As a case study we&#8217;ll draft out the architecture of a simple ecommerce, we start with these three microservices:</p>

<p><strong style="font-weight:800"><em>Order</em></strong> &#8211;  Manages the orders and its lines (e.g. in review, dispatched).<br>
<strong style="font-weight:800"><em>Logistic</em></strong> &#8211; Manages the moving about of the items.<br>
<strong><em style="font-weight:800">Billing</em></strong> &#8211; Manages the company general ledger.
</p>

<p>
When a customers fills his basket with whichever item he wants and completes the payment procedure, we&#8217;ll be generating an order.
</p>

<p>

The <strong>Order</strong> microservice may need to send the information to another microservice(s), for example to the <strong style="font-weight:800">Billing</strong> and the <strong style="font-weight:800">Logistic</strong> microservices.
</p>

<p>
In the HTTPS scenario, the <strong style="font-weight:800">Order</strong> microservice needs to know of the existence of those services, namely <strong style="font-weight:800">Billing</strong>&nbsp;and <strong style="font-weight:800">Logistics</strong>, and of their API structure. 
This poses the following problems:<br>If a third microservice needs to be added to the loop, the code of <strong>Order</strong> needs to be altered directly and API changes may need to cascade to other microservices.
</p>

<p>
Additionally we may have long chains of HTTP requests and an API gateway that needs to manage both internal and client generated traffic. This could slow down our application significantly.
</p>

</blockquote>



<p>Another way to manage the communication between microservices is by using asynchronous messaging; one of the benefits of using async is that it allows a microservice to extend the logic whilst not requiring any alterations in the producers&#8217; source code, thereby following the <a href="https://en.wikipedia.org/wiki/Open%E2%80%93closed_principle">open-closed principle</a>.  </p>



<p>Unfortunately using asynchronous messaging at scale may be quite the challenge on its own, and the python asynchronous ecosystem is unfortunately, still pretty immature leaving developers with little to no reference. </p>



<p>In this article I will present an example implemented using <a href="http://www.celeryproject.org/">Celery</a>, <a href="https://pypi.org/project/attrs/">attrs</a>, and <a href="https://cattrs.readthedocs.io/en/latest/readme.html#cattrs">cattrs</a>, which tries to be as exhaustive as possible.</p>



<h3 class="wp-block-heading">Asynchronous messaging using Celery</h3>



<p>Albeit we can choose among various libraries like <a href="https://pypi.org/project/pika/">pika</a>, I will implement it using Celery and Kombu. </p>



<p>In particular we will create specific <a href="https://kombu.readthedocs.io/en/master/reference/kombu.html#exchange">Topic exchanges</a> that will be named after our microservices, and let each interested microservice subscribe to the various events using <strong>routing_keys</strong>.</p>



<p>We will also define our events using <a href="https://pypi.org/project/attrs/">attrs</a>, it has all the features of python <a href="https://docs.python.org/3/library/dataclasses.html">dataclasses</a> plus some other candy, like <a href="https://www.attrs.org/en/stable/api.html#validators">validation</a> and a wider compatibility, which includes python 2.7 and python 3.4+.</p>



<h3 class="wp-block-heading">The <strong><em>event_manager</em></strong> common package</h3>



<p>Now we will  create a library that will be common among our microservices, we will call it <strong><em>event_manager</em></strong>, the scope of this package is to declare the <strong>Exchanges</strong>, the <strong>dataclasses, &nbsp;</strong>eventually their <strong>versions</strong>, and some <strong>utility</strong> classes.</p>



<h4 class="wp-block-heading">The Order object</h4>



<p>We will represent <strong>Order</strong> and <strong>OrderLine</strong> as dataclasses using <em>attrs</em>, this is not an ORM representation but a minimal representation as a message:</p>



<pre class="wp-block-code"><code>import attr


@attr.s(auto_attribs=True)
class OrderLine:
    id: int
    quantity: int
    price: float


@attr.s
class Order:
    id: int = attr.ib()
    lines: Sequence[OrderLine] = attr.ib(default=list)</code></pre>



<h4 class="wp-block-heading">The event class</h4>



<p>Now we will declare a<em> topic exchange</em>, this will allow us to bind it to multiple queues.</p>



<pre class="wp-block-code"><code>from kombu import Exchange

ORDER_EXCHANGE = Exchange('order', type='topic')</code></pre>



<p>We also create a class, lets call it <strong>Event</strong>, that will help us with abstracting some of the complexity, the class will do a number of things:</p>



<ul><li>register a number of callbacks which will be called when the message is received.</li><li>Use <a href="https://cattrs.readthedocs.io/en/latest/readme.html">cattrs</a> to de/serialize our dataclass</li><li>Create a <em>shared task</em> under the hood.</li></ul>



<p>The class will implement the <a href="https://docs.python.org/3.7/howto/descriptor.html">descriptor protocol</a> so that we will be able to declare each event while building the class.</p>



<pre class="wp-block-code"><code>from ...


Message = TypeVar('Message')


class Event:

    def __init__(self, exchange: Exchange, routing_key: str):
        ...

    def __get__(self, instance: Message, owner: Type[Message]
    ) -> Union['Event', Task]:
        ...

    def register_callback(self, callback: Callable[[Message], Any]):
        ...
</code></pre>



<p>For a full implementation see the code on <a href="https://github.com/zauddelig/celery-attrs-example/blob/master/event_manager/event.py">github</a>.</p>



<p>We can now add a new line to the Order class, as you can see we are setting up a versioning:</p>



<pre class="wp-block-code"><code>
class Order:
    ...
    # represent the submission of an order
    submit = Event(ORDER_EXCHANGE, 'order.v1.submit')
    # represent the cancellation of an order
    chargeback = Event(ORDER_EXCHANGE, 'order.v1.chargeback')
    # other events
 </code></pre>



<h3 class="wp-block-heading">An Order is submitted</h3>



<p>Now the <strong>Order</strong> microservice will be able to create an order message and send events through it:</p>



<pre class="wp-block-code"><code>from event_manager.types.order import Order, OrderLine
order = Order(1, [
    OrderLine(1, 2, 3),
    OrderLine(2, 1, 4.5),
])
order.submit()</code></pre>



<h3 class="wp-block-heading">The Billing Microservice</h3>



<p>In the billing microservice we will need to bind a queue, we will make sure that it will receive the message wathever the version, we will make sure that the message is received regardless of its version:</p>



<pre class="wp-block-preformatted">from kombu import Queue<br><br>from event_manager.exchanges import ORDER_EXCHANGE<br><br>QUEUES = (<br>    Queue(f'billing_order', exchange=ORDER_EXCHANGE,<br>          routing_key='order.*.submit'),<br>)</pre>



<p>And register at least one callback:</p>



<p></p>



<p></p>



<pre class="wp-block-code"><code>from event_manager.types.order import Order


@Order.submit.register_callback
def billing_received(order: Order):
    print(f'billing received a task for order {order}')</code></pre>



<p>You can go check my <a href="https://github.com/zauddelig/celery-attrs-example">repository on github</a> to find a complete example on how this will work.</p>



<p>All in all asynchronous messaging is, likely, the way to go when it comes to the communication between microservices. Unfortunately the ecosystem is still a bit lacking when talking about a framework able to painlessly help developers build and manage complex networks of microservices, on the other hand this means that it is, once again, the time for pioneering new solutions.</p>



<p> Licensed under: <a rel="noreferrer noopener" target="_blank" href="http://creativecommons.org/licenses/by-sa/4.0/">Attribution-ShareAlike 4.0 International</a><br><br>Do you know the difference between <code>list()</code> and <code>[]</code>, if not; head to this <a href="https://pythonright.com/whats-the-difference-between-list-function-and-literal-syntax/">article</a> to read more.<br></p>
<p>The post <a rel="nofollow" href="https://pythonright.com/celery-advanced-routing-techniques/">Celery: Advanced Routing Techniques</a> appeared first on <a rel="nofollow" href="https://pythonright.com">PythonRight</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://pythonright.com/celery-advanced-routing-techniques/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
