<?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>DEV Community: Phước</title>
    <description>The latest articles on DEV Community by Phước (@trviph).</description>
    <link>https://dev.to/trviph</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%2F1229669%2F4fa1186f-d237-4451-b4ef-96929b5d6baa.jpeg</url>
      <title>DEV Community: Phước</title>
      <link>https://dev.to/trviph</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/trviph"/>
    <language>en</language>
    <item>
      <title>Outbox Pattern</title>
      <dc:creator>Phước</dc:creator>
      <pubDate>Sun, 10 Dec 2023 15:30:48 +0000</pubDate>
      <link>https://dev.to/trviph/outbox-pattern-45bn</link>
      <guid>https://dev.to/trviph/outbox-pattern-45bn</guid>
      <description>&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;I'm working on an OMS (Order Management System) that listens to a message queue for orders that are placed and then processes them. There are a few steps involved, as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get the order placement message from the message queue.&lt;/li&gt;
&lt;li&gt;Process the order placement depending on business needs.&lt;/li&gt;
&lt;li&gt;Save the state of the order to the database.&lt;/li&gt;
&lt;li&gt;Publish a new message for the next step to the message queue.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6vzakf5bwtxep0dlh3vt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6vzakf5bwtxep0dlh3vt.png" alt="Steps to process an order placement" width="563" height="249"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is a problem since we need to save the state of the order and publish a message for the next step, and these two operations are not atomic, which means one can fail and the other will not be able to revert. We could run in a situation where the order's state is updated successfully in the database, but no message for the next step is published to the message queue due to an error or network timeout, causing the order to be stuck and not progress any further. This could make the data in our system to be inconsistent and unreliable.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fztiqvxg6dhtzdnf6r18h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fztiqvxg6dhtzdnf6r18h.png" alt="Publishing a new message could failed" width="563" height="249"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can try to have a condition here that if the publishing to the message queue fails, we can retry to deliver the message or revert the order back to its previous status. But what if the system crashed while trying to publish the message or that the retry/revert also failed, how can we revert the state from the database?&lt;/p&gt;

&lt;h2&gt;
  
  
  The solution
&lt;/h2&gt;

&lt;p&gt;The solution I came up with after some research is that we can use the outbox pattern!&lt;/p&gt;

&lt;p&gt;We created a new table called &lt;code&gt;order_outbox&lt;/code&gt; in the database, so every time we update the order state we also insert a new record into the &lt;code&gt;order_outbox&lt;/code&gt; table in the same transaction making them atomic, and having a new message relay to read from the table. The message relay will then publish all unpublished messages it can get from the &lt;code&gt;order_outbox&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4bywvu3wqsaodctvg1ix.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4bywvu3wqsaodctvg1ix.png" alt="Adding a new table order_outbox" width="800" height="377"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A caution
&lt;/h2&gt;

&lt;p&gt;Using the Outbox Pattern will guarantee that our publisher/producer will be an at-least-once publisher. But it may cause duplicated message delivery. So make sure your consumer/subscriber is tolerant of duplicated messages by business requirements or by implementing the Idempotent Consumer pattern.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;This post is a note to myself, so if you find it interesting but hard to understand. You can follow these two links for references.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://microservices.io/patterns/data/transactional-outbox.html" rel="noopener noreferrer"&gt;Microservices Pattern: Transactional outbox - microservices.io&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://codeopinion.com/outbox-pattern-reliably-save-state-publish-events/" rel="noopener noreferrer"&gt;Outbox Pattern: Reliably Save State &amp;amp; Publish Events - codeopinion.com&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>backend</category>
      <category>microservices</category>
      <category>designpatterns</category>
      <category>designsystem</category>
    </item>
  </channel>
</rss>
