[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$f2dgy8wniot6zy":3},{"id":4,"title":5,"description":6,"category":7,"contentHtml":8,"date":9,"createdAt":10,"updatedAt":10},"60084aca-428a-413e-8388-7d1d0d6b22c3","Distributed Transaction Processing: Saga Pattern in Golang","A practical guide to distributed transactions with the saga pattern in Go. Build an orchestrated saga, roll back failed steps with compensating transactions, and retry failed compensations with Kafka retry topics and a dead letter queue.","backend development","\u003Ch2>Prerequisites\u003C\u002Fh2>\n\u003Cp>What do you need to follow along?\u003C\u002Fp>\n\u003Cul>\n\u003Cli>Working knowledge of Golang.\u003C\u002Fli>\n\u003Cli>Go &#x26; Docker installed on your PC.\u003C\u002Fli>\n\u003Cli>Basic knowledge of Kafka. If you need a refresher, my \u003Ca href=\"\u002Fblog\u002F1f6874d4-270c-48e1-9798-324b494c7f0e\">guide on fault-tolerant Kafka pipelines\u003C\u002Fa> covers everything we use here.\u003C\u002Fli>\n\u003Cli>At least 8 hours of sleep (too much to ask for?)\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2>The Monolith\u003C\u002Fh2>\n\u003Cp>Say you have a small e-commerce web app (for simplicity, and also because I want it to match my code examples). You built it as a monolith, and everything works well together.\u003C\u002Fp>\n\u003Cp>In this system, when a user makes a purchase, everything happens in one app with one database. So we can use a database transaction to perform all the operations needed. For simplicity, say our operations are:\u003C\u002Fp>\n\u003Col>\n\u003Cli>Place the order.\u003C\u002Fli>\n\u003Cli>Reserve the stock.\u003C\u002Fli>\n\u003Cli>Process the payment.\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>Three simple enough steps. Since they all run in a single database transaction, if one fails, the database rolls back the previous steps. That all-or-nothing behaviour is one of the guarantees of an ACID transaction.\u003C\u002Fp>\n\u003Ch2>ACID, Defined\u003C\u002Fh2>\n\u003Cp>ACID is an acronym that refers to the set of 4 key properties that define a transaction:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>Atomicity\u003C\u002Fstrong>: Each statement in a transaction (to read, write, update or delete data) is treated as a single unit. Either the entire statement is executed, or none of it is executed.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Consistency\u003C\u002Fstrong>: Ensures that transactions only make changes to tables in predefined, predictable ways. Transactional consistency ensures that corruption or errors in your data do not create unintended consequences for the integrity of your table.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Isolation\u003C\u002Fstrong>: When multiple users are reading and writing from the same table all at once, isolation of their transactions ensures that the concurrent transactions don't interfere with or affect one another. Each request can occur as though they were occurring one by one, even though they're actually occurring simultaneously.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Durability\u003C\u002Fstrong>: Ensures that changes to your data made by successfully executed transactions will be saved, even in the event of system failure.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>ACID transactions ensure the highest possible data reliability and integrity. They ensure that your data never falls into an inconsistent state because of an operation that only partially completes.\u003C\u002Fp>\n\u003Ch2>Splitting Into Microservices\u003C\u002Fh2>\n\u003Cp>Now say your app grows. Traffic picks up, Black Friday is around the corner, and the monolith can't keep up. So you split it into microservices that are loosely coupled, each with its own database, and each able to scale on its own.\u003C\u002Fp>\n\u003Cp>When a user makes a purchase now, the flow changes. The purchase touches three services instead of one:\u003C\u002Fp>\n\u003Col>\n\u003Cli>The order service.\u003C\u002Fli>\n\u003Cli>The inventory service.\u003C\u002Fli>\n\u003Cli>The payment service.\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>There is no single database transaction that can wrap all three anymore. So how do we ensure ACID when one purchase spans every service?\u003C\u002Fp>\n\u003Cp>Easy. We just hope nothing ever fails halfway through a purchase. And if something does? Who cares?\u003C\u002Fp>\n\u003Cp>There, fixed!\u003C\u002Fp>\n\u003Cp>Okay, seriously now. How do we get an ACID-like transaction across different microservices?\u003C\u002Fp>\n\u003Ch2>Distributed Transactions, Defined\u003C\u002Fh2>\n\u003Cp>A distributed transaction is an operation within a distributed environment that spans multiple independent network nodes, databases, or microservices, ensuring that all parts either succeed or fail together as a single atomic unit.\u003C\u002Fp>\n\u003Cp>There are two main ways to approach distributed transactions:\u003C\u002Fp>\n\u003Col>\n\u003Cli>Two-phase commit (2PC).\u003C\u002Fli>\n\u003Cli>The saga pattern.\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>2PC uses a coordinator to run a transaction across every participant in two phases:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>Prepare phase\u003C\u002Fstrong>: The coordinator asks each participant if it can commit. Each participant locks the data it needs and votes yes or no.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Commit phase\u003C\u002Fstrong>: If every participant votes yes, the coordinator tells them all to commit. If any participant votes no, it tells them all to roll back.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>The problem with this is that every participant holds its locks until the coordinator decides. One slow participant, or a coordinator that crashes in the middle, leaves everyone else blocked and waiting.\u003C\u002Fp>\n\u003Cp>In this article, I'll be focusing on the saga pattern, as it is the one used in most production implementations today.\u003C\u002Fp>\n\u003Ch2>The Saga Pattern\u003C\u002Fh2>\n\u003Cp>The saga pattern takes a different approach. Instead of one big transaction that locks every service until everyone agrees, it splits the work into smaller local transactions that each commit on their own.\u003C\u002Fp>\n\u003Cp>In the saga pattern, we implement each business transaction that spans multiple services as a saga. A saga is a reliably coordinated sequence of local transactions. The coordination mechanism, which often uses asynchronous messaging, ensures that the saga finishes: either all steps complete successfully or, if a local transaction fails because it violates a business rule, the changes made by the completed steps are undone by compensating transactions.\u003C\u002Fp>\n\u003Cp>The compensating transactions run in reverse order, so the last step that completed is the first one we undo.\u003C\u002Fp>\n\u003Ch3>Eventual Consistency\u003C\u002Fh3>\n\u003Cp>So how does the data stay consistent? The magic word is \u003Cstrong>eventual consistency\u003C\u002Fstrong>.\u003C\u002Fp>\n\u003Cp>The idea is that the data (the user's order data in our example) stays consistent, but no longer within a single transaction. In practice, there's a slight delay (usually milliseconds) during which the system is inconsistent, but then it catches up. When something fails and has to be retried, as we'll see later, that delay can stretch to a few minutes.\u003C\u002Fp>\n\u003Ch3>Our Order Saga\u003C\u002Fh3>\n\u003Cp>Here is what the saga looks like for our order example:\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"https:\u002F\u002Fres.cloudinary.com\u002Fdb6nohcui\u002Fimage\u002Fupload\u002Fq_auto,f_auto\u002Fv1792370404\u002Fportfiolio-blog\u002Fhwo6wvny84koxnkfmwrd.png\" alt=\"Saga flowchart for the order processing example\">\u003C\u002Fp>\n\u003Cp>When a step fails, the saga only undoes the steps that completed before it. The failed step itself has nothing to undo. For example, if \u003Ccode>process-payment\u003C\u002Fcode> fails, no money was taken, so there is nothing to refund. The saga releases the reserved stock, then cancels the order.\u003C\u002Fp>\n\u003Ch3>Choreography vs Orchestration\u003C\u002Fh3>\n\u003Cp>There are two ways of coordinating sagas:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>Choreography\u003C\u002Fstrong>: Each local transaction publishes domain events that trigger local transactions in other services. There is no central coordinator. Each service listens for events and knows what to do next.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Orchestration\u003C\u002Fstrong>: An orchestrator (an object) tells the participants which local transactions to execute. The whole flow, including the rollback, lives in one place.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>In our Go example, we will be using orchestration.\u003C\u002Fp>\n\u003Ch2>Implementing the Saga in Golang\u003C\u002Fh2>\n\u003Cp>Since we now understand how sagas work, let's implement one in Golang, in our example e-commerce web app (which by now I have forced you to visualize 4 times, you're welcome).\u003C\u002Fp>\n\u003Ch3>Project Structure\u003C\u002Fh3>\n\u003Cp>Here is how the code is laid out:\u003C\u002Fp>\n\u003Cfigure data-rehype-pretty-code-figure=\"\">\u003Cpre tabindex=\"0\" data-language=\"bash\" data-theme=\"vesper github-light\">\u003Ccode data-language=\"bash\" data-theme=\"vesper github-light\" style=\"display: grid;\">\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">cmd\u002Fmain.go\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">                    wires\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> everything\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> together\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">internal\u002Fdomain\u002Fsaga\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">           the\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> reusable\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> saga\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">internal\u002Fdomain\u002Forder\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">          the\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> order\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> model\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">internal\u002Fservice\u002Forder\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">         the\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> order\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> service\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> and\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> the\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> saga\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> steps\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">internal\u002Fadapters\u002Fkafka\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">        producer,\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> consumers,\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> retry\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> topics\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">internal\u002Fadapters\u002Fapi\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">          the\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> HTTP\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> handler\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Ffigure>\n\u003Ch3>The Saga\u003C\u002Fh3>\n\u003Cp>First, we define our saga and its steps, along with the basic functionality like adding a step and executing the saga:\u003C\u002Fp>\n\u003Cfigure data-rehype-pretty-code-figure=\"\">\u003Cpre tabindex=\"0\" data-language=\"go\" data-theme=\"vesper github-light\">\u003Ccode data-language=\"go\" data-theme=\"vesper github-light\" style=\"display: grid;\">\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#8B8B8B94;--shiki-light:#6A737D\">\u002F\u002F internal\u002Fdomain\u002Fsaga\u002Fsaga.go\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">package\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> saga\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">import\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> (\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">errors\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">fmt\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">slices\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">sync\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">type\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> Step\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> struct\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tName       \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tAction     \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">func\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">ctx\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">data\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> map\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">[\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">]\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">interface\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{}) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">error\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tCompensate \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">func\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">ctx\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">data\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> map\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">[\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">]\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">interface\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{}) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">error\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">type\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> Saga\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> struct\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tname  \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tsteps []\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Step\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tmu    \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">sync\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Mutex\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">func\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> New\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">name\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">*\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Saga\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> &#x26;\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Saga\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\tname:  name,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\tsteps: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">make\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">([]\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Step\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\">0\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">),\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">func\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> (\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">s \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">*\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Saga\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">AddStep\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">step\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> Step\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">*\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Saga\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\ts.mu.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Lock\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">()\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\tdefer\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> s.mu.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Unlock\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">()\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\ts.steps \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> append\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(s.steps, step)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> s\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">type\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> ExecutionResult\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> struct\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tSuccess              \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">bool\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tFailedStep           \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tError                \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">error\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tCompletedSteps       []\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tRolledBack           \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">bool\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tPendingCompensations []\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tCompensationError    \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">error\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">func\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> (\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">s \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">*\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Saga\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Execute\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">ctx\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">data\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> map\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">[\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">]\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">interface\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{}) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">ExecutionResult\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\ts.mu.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Lock\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">()\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\tdefer\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> s.mu.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Unlock\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">()\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tcompletedSteps \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> make\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">([]\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\">0\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">len\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(s.steps))\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tresult \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> ExecutionResult\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{Success: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\">true\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\tfor\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> _, step \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> range\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> s.steps {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\tselect\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\tcase\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> &#x3C;-\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">ctx.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Done\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">():\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#8B8B8B94;--shiki-light:#6A737D\">\t\t\t\u002F\u002F Context cancelled, rollback\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\t\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> s.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">fail\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(ctx, step.Name, ctx.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Err\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(), completedSteps, data)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\tdefault\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">:\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\tif\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> err \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> step.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Action\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(ctx, data); err \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">!=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\"> nil\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\t\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> s.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">fail\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(ctx, step.Name, err, completedSteps, data)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\tcompletedSteps \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> append\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(completedSteps, step.Name)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tresult.CompletedSteps \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> completedSteps\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> result\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">func\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> (\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">s \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">*\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Saga\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">fail\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">ctx\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">stepName\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">err\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> error\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">completedSteps\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> []\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">data\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> map\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">[\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">]\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">interface\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{}) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">ExecutionResult\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\ttoCompensate \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> slices.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Clone\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(completedSteps)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tslices.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Reverse\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(toCompensate)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tpending, compErr \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> s.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">compensate\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(context.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">WithoutCancel\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(ctx), toCompensate, data)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> ExecutionResult\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\tSuccess:              \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\">false\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\tFailedStep:           stepName,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\tError:                err,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\tCompletedSteps:       completedSteps,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\tRolledBack:           compErr \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">==\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\"> nil\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\tPendingCompensations: pending,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\tCompensationError:    compErr,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">func\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> (\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">s \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">*\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Saga\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Compensate\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">ctx\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">stepNames\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> []\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">data\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> map\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">[\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">]\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">interface\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{}) ([]\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">error\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\ts.mu.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Lock\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">()\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\tdefer\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> s.mu.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Unlock\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">()\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> s.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">compensate\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(ctx, stepNames, data)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">func\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> (\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">s \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">*\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Saga\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">compensate\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">ctx\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">stepNames\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> []\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">data\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> map\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">[\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">]\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">interface\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{}) ([]\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">error\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tstepMap \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> make\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">map\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">[\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">]\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Step\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\tfor\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> _, step \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> range\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> s.steps {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\tstepMap[step.Name] \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> step\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\tvar\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> failed []\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\tvar\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> errs []\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">error\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\tfor\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> _, stepName \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> range\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> stepNames {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\tstep, ok \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> stepMap[stepName]\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\tif\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> !\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">ok {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\t\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\"> nil\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, fmt.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Errorf\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"saga \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%s\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> has no step \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%q\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, s.name, stepName)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\tif\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> step.Compensate \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">!=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\"> nil\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\t\tif\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> err \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> step.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Compensate\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(ctx, data); err \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">!=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\"> nil\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t\t\tfailed \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> append\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(failed, stepName)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t\t\terrs \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> append\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(errs, fmt.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Errorf\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"compensate \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%s\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%w\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, stepName, err))\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> failed, errors.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Join\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(errs\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">...\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Ffigure>\n\u003Cp>So in the code above, we define a \u003Ccode>Step\u003C\u002Fcode>, the \u003Ccode>Saga\u003C\u002Fcode> that holds the steps, and the functions that run and undo them:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>Step\u003C\u002Fstrong>: Each step has a name, an \u003Ccode>Action\u003C\u002Fcode> (the local transaction) and a \u003Ccode>Compensate\u003C\u002Fcode> (the function that undoes it). Both receive the same \u003Ccode>data\u003C\u002Fcode> map, so a step can leave something behind for later steps or for its own compensation. For example, the payment step saves a \u003Ccode>payment_id\u003C\u002Fcode> that the refund needs.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>AddStep\u003C\u002Fstrong>: It returns the saga itself, so we can chain steps together when we build the saga.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Execute\u003C\u002Fstrong>: It runs the steps in order. Before each step, it checks if the context was cancelled. If a step fails, it stops and hands over to \u003Ccode>fail\u003C\u002Fcode>. Every step that succeeds gets added to \u003Ccode>completedSteps\u003C\u002Fcode>, which is how the saga knows what to undo later.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>fail\u003C\u002Fstrong>: It reverses the completed steps and runs their compensations, so the last thing we did is the first thing we undo. It uses \u003Ccode>context.WithoutCancel(ctx)\u003C\u002Fcode> because a rollback has to finish even when the app is shutting down. We don't want to stop halfway through undoing an order.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>compensate\u003C\u002Fstrong>: It runs each compensation and keeps going even when one fails, so one stuck step doesn't stop the others from being undone. Any compensation that fails is collected into a list, and \u003Ccode>errors.Join\u003C\u002Fcode> combines all their errors into one.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Compensate\u003C\u002Fstrong>: This is the public version of \u003Ccode>compensate\u003C\u002Fcode>. We will use it later to retry the compensations that failed.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>The \u003Ccode>ExecutionResult\u003C\u002Fcode> tells the caller exactly how things went:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Ccode>Success\u003C\u002Fcode> is true when every step completed.\u003C\u002Fli>\n\u003Cli>\u003Ccode>RolledBack\u003C\u002Fcode> is true when a step failed but every compensation worked.\u003C\u002Fli>\n\u003Cli>\u003Ccode>PendingCompensations\u003C\u002Fcode> lists the compensations that failed, so we can retry them.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch3>The Order Model\u003C\u002Fh3>\n\u003Cp>Next, let's define our order structure:\u003C\u002Fp>\n\u003Cfigure data-rehype-pretty-code-figure=\"\">\u003Cpre tabindex=\"0\" data-language=\"go\" data-theme=\"vesper github-light\">\u003Ccode data-language=\"go\" data-theme=\"vesper github-light\" style=\"display: grid;\">\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#8B8B8B94;--shiki-light:#6A737D\">\u002F\u002F internal\u002Fdomain\u002Forder\u002Forder.go\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">package\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> order\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">import\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> (\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">errors\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">fmt\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">var\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> ErrInvalidOrder \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> errors.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">New\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"invalid order\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">type\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> OrderStatus\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> string\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">type\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> PaymentStatus\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> string\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">const\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> (\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">\tStatusProcessing\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> OrderStatus\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">   =\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> \"PROCESSING\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">\tPaymentPaid\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">      PaymentStatus\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> \"PAID\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">type\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> Address\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> struct\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tStreet     \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> `json:\"street\"`\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tCity       \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> `json:\"city\"`\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tState      \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> `json:\"state\"`\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tCountry    \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> `json:\"country\"`\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tPostalCode \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> `json:\"postal_code,omitempty\"`\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">type\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> OrderItem\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> struct\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tQuantity  \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">int64\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> `json:\"quantity\"`\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tUnitPrice \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">int64\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> `json:\"unit_price\"`\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tTotal     \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">int64\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> `json:\"total\"`\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">type\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> Order\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> struct\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tID              \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">        `json:\"id\"`\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tStatus          \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">OrderStatus\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">   `json:\"status\"`\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tUserID          \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">        `json:\"user_id\"`\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tProductID       \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">        `json:\"product_id\"`\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tItem            \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">OrderItem\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">     `json:\"item\"`\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tShippingAddress \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Address\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">       `json:\"shipping_address\"`\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tPaymentStatus   \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">PaymentStatus\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> `json:\"payment_status\"`\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">func\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> (\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">o \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Order\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Validate\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">() \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">error\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\tswitch\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\tcase\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> o.UserID \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">==\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> \"\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">:\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> fmt.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Errorf\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%w\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">: user_id is required\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, ErrInvalidOrder)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\tcase\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> o.ProductID \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">==\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> \"\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">:\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> fmt.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Errorf\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%w\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">: product_id is required\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, ErrInvalidOrder)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\tcase\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> o.Item.Quantity \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">&#x3C;=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\"> 0\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">:\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> fmt.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Errorf\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%w\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">: quantity must be greater than 0\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, ErrInvalidOrder)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\tcase\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> o.Item.UnitPrice \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">&#x3C;\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\"> 0\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">:\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> fmt.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Errorf\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%w\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">: unit_price cannot be negative\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, ErrInvalidOrder)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\"> nil\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Ffigure>\n\u003Cp>This is a plain order with a single item and a shipping address. \u003Ccode>Validate\u003C\u002Fcode> wraps every error with \u003Ccode>ErrInvalidOrder\u003C\u002Fcode>. That way, any code further up can check \u003Ccode>errors.Is(err, order.ErrInvalidOrder)\u003C\u002Fcode> and know the order itself was bad, without parsing error messages. Our API uses this to return a \u003Ccode>422\u003C\u002Fcode> instead of a \u003Ccode>500\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Ch3>The Order Service\u003C\u002Fh3>\n\u003Cp>To test our saga, we need to be able to place orders. So let's define our order service and the steps a placed order goes through:\u003C\u002Fp>\n\u003Cfigure data-rehype-pretty-code-figure=\"\">\u003Cpre tabindex=\"0\" data-language=\"go\" data-theme=\"vesper github-light\">\u003Ccode data-language=\"go\" data-theme=\"vesper github-light\" style=\"display: grid;\">\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#8B8B8B94;--shiki-light:#6A737D\">\u002F\u002F internal\u002Fservice\u002Forder\u002Forder.go\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">package\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> order\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">import\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> (\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">crypto\u002Frand\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">encoding\u002Fhex\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">fmt\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">log\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">github.com\u002Fumohsamuel\u002Fdistributed-transactions\u002Finternal\u002Fdomain\u002Forder\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">github.com\u002Fumohsamuel\u002Fdistributed-transactions\u002Finternal\u002Fdomain\u002Fsaga\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">type\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> Events\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> interface\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">\tOrderCreated\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">ctx\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">o\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> order\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Order\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">error\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">\tCompensationFailed\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">ctx\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">orderID\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">steps\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> []\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">data\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> map\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">[\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">]\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">interface\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{}, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">cause\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> error\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">error\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">type\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> Service\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> struct\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tevents    \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Events\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\torders    \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">*\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">OrderService\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tinventory \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">*\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">InventoryService\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tpayments  \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">*\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">PaymentService\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">func\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> NewService\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">events\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> Events\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">*\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Service\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> &#x26;\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Service\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\tevents:    events,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\torders:    \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">&#x26;\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">OrderService\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{},\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\tinventory: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">&#x26;\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">InventoryService\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{releaseAttempts: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">make\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">map\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">[\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">]\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">int\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">)},\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\tpayments:  \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">&#x26;\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">PaymentService\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{},\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">func\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> (\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">s \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">*\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Service\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">PlaceOrder\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">ctx\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">o\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> order\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Order\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) (\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">order\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Order\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">error\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\tif\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> err \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> o.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Validate\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(); err \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">!=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\"> nil\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> order\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Order\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{}, err\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tid, err \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> newOrderID\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">()\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\tif\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> err \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">!=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\"> nil\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> order\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Order\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{}, err\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\to.ID \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> id\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\to.Status \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> order.StatusProcessing\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\to.PaymentStatus \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> \"\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\to.Item.Total \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> o.Item.Quantity \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">*\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> o.Item.UnitPrice\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\tif\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> err \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> s.events.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">OrderCreated\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(ctx, o); err \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">!=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\"> nil\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> order\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Order\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{}, fmt.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Errorf\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"publish order created: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%w\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, err)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> o, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">nil\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#8B8B8B94;--shiki-light:#6A737D\">\u002F\u002F ProcessOrder runs the order saga. It is the entry point for the Kafka consumer.\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">func\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> (\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">s \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">*\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Service\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">ProcessOrder\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">ctx\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">o\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> order\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Order\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">error\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\tif\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> err \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> o.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Validate\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(); err \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">!=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\"> nil\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> err\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tdata \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> map\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">[\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">]\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">interface\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{}{\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\t\"order_id\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">:   o.ID,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\t\"product_id\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">: o.ProductID,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\t\"quantity\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">:   \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">int\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(o.Item.Quantity),\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\t\"amount\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">:     \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">float64\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(o.Item.Total),\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tresult \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> s.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">newSaga\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">().\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Execute\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(ctx, data)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\tif\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> !\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">result.Success {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\tif\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> !\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">result.RolledBack {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\t\tif\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> err \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> s.events.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">CompensationFailed\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(ctx, o.ID, result.PendingCompensations, data, result.CompensationError); err \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">!=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\"> nil\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\t\t\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> fmt.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Errorf\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"order \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%s\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">: schedule compensation retry: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%w\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, o.ID, err)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\t\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> fmt.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Errorf\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"order \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%s\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> failed at step \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%q\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%w\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">; compensation retry scheduled: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%v\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, o.ID, result.FailedStep, result.Error, result.CompensationError)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> fmt.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Errorf\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"order \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%s\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> failed at step \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%q\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> and was rolled back: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%w\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, o.ID, result.FailedStep, result.Error)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tlog.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Printf\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"Order \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%s\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> completed: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%v\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, o.ID, result.CompletedSteps)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\"> nil\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">func\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> (\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">s \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">*\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Service\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">RetryCompensation\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">ctx\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">steps\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> []\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">data\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> map\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">[\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">]\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">interface\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{}) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">error\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\tif\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> _, err \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> s.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">newSaga\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">().\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Compensate\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(ctx, steps, data); err \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">!=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\"> nil\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> err\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tlog.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Printf\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"Order \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%v\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> rolled back after retrying compensations: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%v\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, data[\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"order_id\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">], steps)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\"> nil\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#8B8B8B94;--shiki-light:#6A737D\">\u002F\u002F newSaga builds a fresh saga per order, since Execute holds the saga's lock for\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#8B8B8B94;--shiki-light:#6A737D\">\u002F\u002F the whole run and a shared instance would process one order at a time.\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">func\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> (\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">s \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">*\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Service\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">newSaga\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">() \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">*\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">saga\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Saga\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> saga.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">New\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"order-processing\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">).\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">\t\tAddStep\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">saga\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Step\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t\tName:       \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"create-order\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t\tAction:     s.orders.CreateOrder,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t\tCompensate: s.orders.CancelOrder,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t}).\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">\t\tAddStep\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">saga\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Step\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t\tName:       \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"reserve-inventory\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t\tAction:     s.inventory.ReserveStock,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t\tCompensate: s.inventory.ReleaseStock,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t}).\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">\t\tAddStep\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">saga\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Step\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t\tName:       \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"process-payment\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t\tAction:     s.payments.ProcessPayment,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t\tCompensate: s.payments.RefundPayment,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t})\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">func\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> newOrderID\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">() (\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">error\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tb \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> make\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">([]\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">byte\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\">8\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\tif\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> _, err \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> rand.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Read\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(b); err \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">!=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\"> nil\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> \"\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, fmt.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Errorf\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"generate order id: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%w\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, err)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> \"ord_\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> +\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> hex.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">EncodeToString\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(b), \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">nil\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Ffigure>\n\u003Cp>The service has two jobs: accepting orders and processing them.\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>Events\u003C\u002Fstrong>: This interface is how the service talks to the outside world. The service doesn't know Kafka exists. It just calls \u003Ccode>OrderCreated\u003C\u002Fcode> or \u003Ccode>CompensationFailed\u003C\u002Fcode>, and the Kafka adapter (which we will see soon) handles the rest. This also makes the service easy to test with a fake.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>PlaceOrder\u003C\u002Fstrong>: This is what the API calls. It validates the order, gives it an ID, calculates the total and publishes an \u003Ccode>OrderCreated\u003C\u002Fcode> event. It does not run the saga. It returns straight away with a \u003Ccode>PROCESSING\u003C\u002Fcode> status, and the real work happens in the background when a consumer picks up the event.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>ProcessOrder\u003C\u002Fstrong>: This is what the Kafka consumer calls. It copies what the steps need into the \u003Ccode>data\u003C\u002Fcode> map and runs the saga. There are three possible outcomes:\n\u003Cul>\n\u003Cli>Every step worked, so we log it and we are done.\u003C\u002Fli>\n\u003Cli>A step failed, but every compensation worked. The order failed cleanly, so we return an error for the logs and that's the end of it. There is nothing to retry.\u003C\u002Fli>\n\u003Cli>A step failed, and some compensations failed too. The system is now half rolled back, which is the one case we can't leave alone. So we publish the failed compensations with \u003Ccode>CompensationFailed\u003C\u002Fcode>, and they get retried later.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003C\u002Fli>\n\u003Cli>\u003Cstrong>RetryCompensation\u003C\u002Fstrong>: This is what the retry consumers call. It only runs the compensations that failed, using the \u003Ccode>Compensate\u003C\u002Fcode> method from our saga. It never reruns the saga itself.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>newSaga\u003C\u002Fstrong>: This is where we define the actual flow. Each step is paired with its compensation, and the order we add them in is the order they run in.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch3>The Steps and Their Compensations\u003C\u002Fh3>\n\u003Cp>Next, each step and its compensating action:\u003C\u002Fp>\n\u003Cfigure data-rehype-pretty-code-figure=\"\">\u003Cpre tabindex=\"0\" data-language=\"go\" data-theme=\"vesper github-light\">\u003Ccode data-language=\"go\" data-theme=\"vesper github-light\" style=\"display: grid;\">\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#8B8B8B94;--shiki-light:#6A737D\">\u002F\u002F internal\u002Fservice\u002Forder\u002Fsteps.go\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">package\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> order\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">import\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> (\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">fmt\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">sync\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">type\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> OrderService\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> struct\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">func\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> (\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">o \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">*\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">OrderService\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">CreateOrder\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">ctx\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">data\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> map\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">[\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">]\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">interface\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{}) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">error\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\torderID \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> data[\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"order_id\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">].(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tfmt.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Printf\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"Creating order \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%s\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#005CC5\">\\n\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, orderID)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tdata[\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"order_created\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">] \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\"> true\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\"> nil\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">func\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> (\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">o \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">*\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">OrderService\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">CancelOrder\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">ctx\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">data\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> map\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">[\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">]\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">interface\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{}) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">error\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\torderID \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> data[\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"order_id\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">].(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tfmt.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Printf\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"Cancelling order \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%s\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#005CC5\">\\n\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, orderID)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\"> nil\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">const\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\"> releaseFailures\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\"> 2\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">type\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> InventoryService\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> struct\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tmu              \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">sync\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Mutex\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\treleaseAttempts \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">map\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">[\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">]\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">int\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">func\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> (\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">i \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">*\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">InventoryService\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">ReserveStock\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">ctx\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">data\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> map\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">[\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">]\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">interface\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{}) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">error\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tproductID \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> data[\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"product_id\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">].(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tquantity \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> number\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(data[\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"quantity\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">])\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tfmt.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Printf\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"Reserving \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%d\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> units of product \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%s\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#005CC5\">\\n\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, quantity, productID)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tdata[\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"stock_reserved\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">] \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\"> true\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\"> nil\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">func\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> (\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">i \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">*\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">InventoryService\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">ReleaseStock\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">ctx\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">data\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> map\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">[\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">]\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">interface\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{}) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">error\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\torderID \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> data[\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"order_id\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">].(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tproductID \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> data[\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"product_id\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">].(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tquantity \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> number\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(data[\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"quantity\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">])\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\ti.mu.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Lock\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">()\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\ti.releaseAttempts[orderID]\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">++\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tattempt \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> i.releaseAttempts[orderID]\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\ti.mu.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Unlock\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">()\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\tif\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> attempt \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">&#x3C;=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> releaseFailures {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> fmt.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Errorf\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"inventory service unavailable (release attempt \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%d\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">)\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, attempt)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tfmt.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Printf\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"Releasing \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%d\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> units of product \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%s\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> (release attempt \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%d\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">)\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#005CC5\">\\n\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, quantity, productID, attempt)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\"> nil\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">func\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> number\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">v\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> interface\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{}) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">int\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\tswitch\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> n \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> v.(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">type\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\tcase\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> int\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">:\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> n\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\tcase\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> float64\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">:\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> int\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(n)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\"> 0\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">const\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\"> paymentLimit\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\"> 1000\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">type\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> PaymentService\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> struct\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">func\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> (\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">p \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">*\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">PaymentService\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">ProcessPayment\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">ctx\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">data\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> map\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">[\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">]\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">interface\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{}) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">error\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tamount \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> data[\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"amount\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">].(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">float64\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\tif\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> amount \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">>\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> paymentLimit {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> fmt.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Errorf\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"payment of $\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%.2f\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> declined: insufficient funds\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, amount)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tfmt.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Printf\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"Processing payment of $\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%.2f\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#005CC5\">\\n\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, amount)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tdata[\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"payment_id\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">] \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> \"pay_123456\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\"> nil\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">func\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> (\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">p \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">*\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">PaymentService\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">RefundPayment\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">ctx\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">data\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> map\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">[\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">]\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">interface\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{}) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">error\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\tif\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> paymentID, ok \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> data[\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"payment_id\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">].(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">); ok {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\tfmt.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Printf\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"Refunding payment \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%s\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#005CC5\">\\n\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, paymentID)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\"> nil\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Ffigure>\n\u003Cp>Of course, these are mocked for the sake of simplicity. In a real system, these would call other services over HTTP, gRPC, etc. Here, we mock everything, log each action, and simulate failures so we can follow along in the console:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>ProcessPayment\u003C\u002Fstrong>: Any payment above \u003Ccode>paymentLimit\u003C\u002Fcode> ($1000) gets declined. This is how we make the saga fail and roll back. When a payment works, it saves a \u003Ccode>payment_id\u003C\u002Fcode> in the \u003Ccode>data\u003C\u002Fcode> map, which \u003Ccode>RefundPayment\u003C\u002Fcode> would need to refund it.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>ReleaseStock\u003C\u002Fstrong>: This simulates an inventory service that is down. It keeps a count of release attempts for each order and fails the first \u003Ccode>releaseFailures\u003C\u002Fcode> attempts. With it set to \u003Ccode>2\u003C\u002Fcode>, the first release fails, the first retry fails, and the second retry works. Set it to \u003Ccode>4\u003C\u002Fcode> or more if you want to see the message land in the DLQ.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>One more thing. \u003Ccode>RefundPayment\u003C\u002Fcode> never actually runs in our example. Payment is the last step, so if it fails there is no completed payment to refund, and if it works there is nothing to undo.\u003C\u002Fp>\n\u003Cp>Here is how a failed compensation moves through the retries:\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"https:\u002F\u002Fres.cloudinary.com\u002Fdb6nohcui\u002Fimage\u002Fupload\u002Fq_auto,f_auto\u002Fv1792370408\u002Fportfiolio-blog\u002Fjs36zmzhwdvh2y6go11h.png\" alt=\"Compensation retry flow through the Kafka retry topics\">\u003C\u002Fp>\n\u003Ch3>The Kafka Adapter\u003C\u002Fh3>\n\u003Cp>Next, the order adapter for Kafka:\u003C\u002Fp>\n\u003Cfigure data-rehype-pretty-code-figure=\"\">\u003Cpre tabindex=\"0\" data-language=\"go\" data-theme=\"vesper github-light\">\u003Ccode data-language=\"go\" data-theme=\"vesper github-light\" style=\"display: grid;\">\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#8B8B8B94;--shiki-light:#6A737D\">\u002F\u002F internal\u002Fadapters\u002Fkafka\u002Forders.go\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">package\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> kafka\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">import\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> (\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">encoding\u002Fjson\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">fmt\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">github.com\u002FIBM\u002Fsarama\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">github.com\u002Fumohsamuel\u002Fdistributed-transactions\u002Finternal\u002Fdomain\u002Forder\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">type\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> OrderPublisher\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> struct\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tproducer \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">*\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">KafkaProducer\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\trouter   \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">*\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">RetryRouter\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">func\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> NewOrderPublisher\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">producer\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> *\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">KafkaProducer\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">router\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> *\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">RetryRouter\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">*\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">OrderPublisher\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> &#x26;\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">OrderPublisher\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{producer: producer, router: router}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">func\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> (\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">p \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">*\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">OrderPublisher\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">OrderCreated\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">ctx\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">o\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> order\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Order\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">error\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tvalue, err \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> json.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Marshal\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(o)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\tif\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> err \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">!=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\"> nil\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> fmt.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Errorf\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"encode order: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%w\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, err)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> p.producer.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">send\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">&#x26;\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">sarama\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">ProducerMessage\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\tTopic: CREATED.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">String\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(),\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\tKey:   sarama.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">StringEncoder\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(o.ID),\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\tValue: sarama.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">ByteEncoder\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(value),\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t})\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">type\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> compensationMessage\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> struct\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tOrderID \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">                 `json:\"order_id\"`\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tSteps   []\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">               `json:\"steps\"`\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tData    \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">map\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">[\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">]\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">interface\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{} \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">`json:\"data\"`\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">func\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> (\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">p \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">*\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">OrderPublisher\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">CompensationFailed\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">ctx\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">orderID\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">steps\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> []\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">data\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> map\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">[\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">]\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">interface\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{}, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">cause\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> error\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">error\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tvalue, err \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> json.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Marshal\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">compensationMessage\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{OrderID: orderID, Steps: steps, Data: data})\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\tif\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> err \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">!=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\"> nil\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> fmt.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Errorf\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"encode compensation: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%w\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, err)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> p.router.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Schedule\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">([]\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">byte\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(orderID), value, CREATED.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">String\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(), cause)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">type\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> OrderProcessor\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> interface\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">\tProcessOrder\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">ctx\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">o\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> order\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Order\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">error\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">func\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> OrderCreatedHandler\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">orders\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> OrderProcessor\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">HandlerFunc\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> func\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">ctx\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">msg\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> Message\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">error\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\tvar\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> o \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">order\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Order\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\tif\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> err \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> json.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Unmarshal\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(msg.Value, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">&#x26;\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">o); err \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">!=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\"> nil\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\t\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> fmt.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Errorf\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"decode order: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%w\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, err)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> orders.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">ProcessOrder\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(ctx, o)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">type\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> CompensationRetrier\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> interface\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">\tRetryCompensation\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">ctx\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">steps\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> []\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">data\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> map\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">[\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">]\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">interface\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{}) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">error\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">func\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> CompensationHandler\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">orders\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> CompensationRetrier\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">HandlerFunc\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> func\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">ctx\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">msg\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> Message\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">error\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\tvar\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> c \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">compensationMessage\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\tif\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> err \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> json.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Unmarshal\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(msg.Value, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">&#x26;\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">c); err \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">!=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\"> nil\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\t\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> Permanent\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(fmt.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Errorf\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"decode compensation: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%w\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, err))\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> orders.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">RetryCompensation\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(ctx, c.Steps, c.Data)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Ffigure>\n\u003Cp>This is the bridge between our service and Kafka. The \u003Ccode>OrderPublisher\u003C\u002Fcode> is what we pass to the service as its \u003Ccode>Events\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>OrderCreated\u003C\u002Fstrong>: It publishes the order to the \u003Ccode>created\u003C\u002Fcode> topic, using the order ID as the message key. Kafka sends messages with the same key to the same partition, so all messages for one order stay in order.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>compensationMessage\u003C\u002Fstrong>: This is what travels through the retry topics. Notice it carries the failed steps and the saga's \u003Ccode>data\u003C\u002Fcode>, not the order. This is the important part: a retry only runs the compensations that are still pending, and never reruns the saga from the top. It also carries \u003Ccode>data\u003C\u002Fcode> and not just the order, because steps add things to it as they run (like the \u003Ccode>payment_id\u003C\u002Fcode>).\u003C\u002Fli>\n\u003Cli>\u003Cstrong>CompensationFailed\u003C\u002Fstrong>: It encodes the message and calls \u003Ccode>Schedule\u003C\u002Fcode> on the retry router, which sends it to the first retry topic.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>OrderCreatedHandler\u003C\u002Fstrong> and \u003Cstrong>CompensationHandler\u003C\u002Fstrong>: These decode the message and call the right method on the service. The first one handles new orders from the \u003Ccode>created\u003C\u002Fcode> topic. The second one handles compensations from the retry topics. If a compensation message can't even be decoded, retrying won't fix it, so we mark it \u003Ccode>Permanent\u003C\u002Fcode> and the router sends it straight to the DLQ.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>In my implementation, I also added the retry router, the retry consumers, the DLQ and a graceful shutdown. For the sake of simplicity, and to keep this guide short and to the point, I will skip their code here. The retry tiers and DLQ work exactly like they do in my \u003Ca href=\"\u002Fblog\u002F1f6874d4-270c-48e1-9798-324b494c7f0e\">Kafka pipelines guide\u003C\u002Fa>, and the shutdown is covered in my \u003Ca href=\"\u002Fblog\u002F2fbbf043-1b2e-45ab-bfc9-b7eafd89926c\">graceful shutdown guide\u003C\u002Fa>. If you want to have a look, you can go through the repository linked at the end of this guide.\u003C\u002Fp>\n\u003Ch3>The API Adapter\u003C\u002Fh3>\n\u003Cp>Next, we add the order API adapter, since we will be serving orders through HTTP requests (ideally, that's how requests would come in for a traditional app):\u003C\u002Fp>\n\u003Cfigure data-rehype-pretty-code-figure=\"\">\u003Cpre tabindex=\"0\" data-language=\"go\" data-theme=\"vesper github-light\">\u003Ccode data-language=\"go\" data-theme=\"vesper github-light\" style=\"display: grid;\">\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#8B8B8B94;--shiki-light:#6A737D\">\u002F\u002F internal\u002Fadapters\u002Fapi\u002Forder.go\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">package\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> api\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">import\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> (\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">errors\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">log\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">net\u002Fhttp\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">github.com\u002Fgin-gonic\u002Fgin\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">github.com\u002Fumohsamuel\u002Fdistributed-transactions\u002Finternal\u002Fdomain\u002Forder\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">type\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> OrderPlacer\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> interface\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">\tPlaceOrder\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">ctx\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">o\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> order\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Order\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) (\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">order\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Order\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">error\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">type\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> OrderHandler\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> struct\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\torders \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">OrderPlacer\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">func\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> NewOrderHandler\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">orders\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> OrderPlacer\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">*\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">OrderHandler\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> &#x26;\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">OrderHandler\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{orders: orders}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">func\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> (\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">h \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">*\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">OrderHandler\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Register\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">r\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> gin\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">IRouter\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tr.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">POST\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u002Forders\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, h.createOrder)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">type\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> createOrderRequest\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> struct\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tUserID          \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">         `json:\"user_id\" binding:\"required\"`\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tProductID       \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">         `json:\"product_id\" binding:\"required\"`\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tQuantity        \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">int64\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">          `json:\"quantity\" binding:\"required,gt=0\"`\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tUnitPrice       \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">int64\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">          `json:\"unit_price\" binding:\"gte=0\"`\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tShippingAddress \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">addressRequest\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> `json:\"shipping_address\" binding:\"required\"`\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">type\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> addressRequest\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> struct\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tStreet     \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> `json:\"street\" binding:\"required\"`\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tCity       \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> `json:\"city\" binding:\"required\"`\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tState      \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> `json:\"state\"`\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tCountry    \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> `json:\"country\" binding:\"required\"`\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tPostalCode \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> `json:\"postal_code\"`\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">type\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> createOrderResponse\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> struct\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tOrderID \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">            `json:\"order_id\"`\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tStatus  \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">order\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">OrderStatus\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> `json:\"status\"`\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">func\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> (\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">req \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">createOrderRequest\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">toDomain\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">() \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">order\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Order\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\treturn\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> order\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Order\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\tUserID:    req.UserID,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\tProductID: req.ProductID,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\tItem: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">order\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">OrderItem\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t\tQuantity:  req.Quantity,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t\tUnitPrice: req.UnitPrice,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t},\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\tShippingAddress: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">order\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Address\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t\tStreet:     req.ShippingAddress.Street,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t\tCity:       req.ShippingAddress.City,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t\tState:      req.ShippingAddress.State,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t\tCountry:    req.ShippingAddress.Country,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t\tPostalCode: req.ShippingAddress.PostalCode,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t},\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">func\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> (\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">h \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">*\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">OrderHandler\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">createOrder\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">c\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> *\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">gin\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\tvar\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> req \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">createOrderRequest\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\tif\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> err \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> c.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">ShouldBindJSON\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">&#x26;\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">req); err \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">!=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\"> nil\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\tc.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">JSON\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(http.StatusBadRequest, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">gin\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">H\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"error\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">: err.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Error\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">()})\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\treturn\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tplaced, err \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> h.orders.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">PlaceOrder\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(c.Request.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(), req.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">toDomain\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">())\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\tif\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> err \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">!=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\"> nil\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">\t\twriteError\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(c, err)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\treturn\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tc.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">JSON\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(http.StatusAccepted, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">createOrderResponse\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\tOrderID: placed.ID,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\tStatus:  placed.Status,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t})\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">func\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> writeError\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">c\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> *\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">gin\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#E36209\">err\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> error\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">) {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\tswitch\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\tcase\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> errors.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Is\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(err, order.ErrInvalidOrder):\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\tc.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">JSON\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(http.StatusUnprocessableEntity, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">gin\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">H\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"error\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">: err.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Error\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">()})\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\tdefault\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">:\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\tlog.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Printf\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%s\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\"> %s\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%v\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, c.Request.Method, c.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">FullPath\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(), err)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\tc.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">JSON\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(http.StatusInternalServerError, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">gin\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">H\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"error\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"something went wrong, please try again\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">})\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Ffigure>\n\u003Cp>The handler keeps the HTTP details away from our domain:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>createOrderRequest\u003C\u002Fstrong>: The \u003Ccode>binding\u003C\u002Fcode> tags let Gin validate the request body for us. A missing field or a quantity of \u003Ccode>0\u003C\u002Fcode> gets rejected with a \u003Ccode>400\u003C\u002Fcode> before it ever reaches the service.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>toDomain\u003C\u002Fstrong>: It converts the request into our \u003Ccode>order.Order\u003C\u002Fcode>. This keeps the JSON shape of the API separate from the order model, so either can change without breaking the other.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>writeError\u003C\u002Fstrong>: It maps our errors to status codes. An invalid order gets a \u003Ccode>422\u003C\u002Fcode>, and anything else gets a \u003Ccode>500\u003C\u002Fcode> with a generic message, so we don't leak internal errors to the user.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch3>Wiring Everything Together\u003C\u002Fh3>\n\u003Cp>Next, we wire everything together in main:\u003C\u002Fp>\n\u003Cfigure data-rehype-pretty-code-figure=\"\">\u003Cpre tabindex=\"0\" data-language=\"go\" data-theme=\"vesper github-light\">\u003Ccode data-language=\"go\" data-theme=\"vesper github-light\" style=\"display: grid;\">\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#8B8B8B94;--shiki-light:#6A737D\">\u002F\u002F cmd\u002Fmain.go\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">package\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> main\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">import\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> (\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">context\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">errors\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">log\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">net\u002Fhttp\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">os\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">os\u002Fsignal\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">sync\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">syscall\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">time\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">github.com\u002Fgin-gonic\u002Fgin\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">github.com\u002Fumohsamuel\u002Fdistributed-transactions\u002Finternal\u002Fadapters\u002Fapi\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\t\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">github.com\u002Fumohsamuel\u002Fdistributed-transactions\u002Finternal\u002Fadapters\u002Fkafka\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tordersvc \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">github.com\u002Fumohsamuel\u002Fdistributed-transactions\u002Finternal\u002Fservice\u002Forder\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">func\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> main\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">() {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tbrokersUrl \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> []\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"localhost:9092\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tctx, stop \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> signal.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">NotifyContext\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(context.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Background\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(), os.Interrupt, syscall.SIGTERM)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\tdefer\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> stop\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">()\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tproducer, err \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> kafka.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">NewKafkaProducer\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(brokersUrl)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\tif\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> err \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">!=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\"> nil\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\tlog.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Fatalf\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"Failed to initialize Kafka producer: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%v\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, err)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\tdefer\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> producer.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Close\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">()\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\trouter \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> kafka.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">NewRetryRouter\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(producer, kafka.RetryTopics, kafka.DLQ.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">String\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">())\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\torders \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> ordersvc.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">NewService\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(kafka.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">NewOrderPublisher\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(producer, router))\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tgroups \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> []\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">struct\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\tgroup  \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">kafka\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">ConsumerGroup\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\ttopic  \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">kafka\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Topics\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\thandle \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">kafka\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">HandlerFunc\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\trouter \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">*\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">kafka\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">RetryRouter\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\tdelay  \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">time\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Duration\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t}{\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t{kafka.ORDERS_MAIN_GROUP, kafka.CREATED, kafka.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">OrderCreatedHandler\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(orders), \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">nil\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\">0\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">},\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t{kafka.ORDERS_1M_RETRY_GROUP, kafka.RETRY_1M, kafka.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">CompensationHandler\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(orders), router, time.Second},\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t{kafka.ORDERS_5M_RETRY_GROUP, kafka.RETRY_5M, kafka.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">CompensationHandler\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(orders), router, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\">5\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> *\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> time.Second},\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t{kafka.ORDERS_10M_RETRY_GROUP, kafka.RETRY_10M, kafka.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">CompensationHandler\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(orders), router, \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\">10\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> *\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> time.Second},\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\tvar\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> wg \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">sync\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">WaitGroup\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\tfor\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> _, g \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> range\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> groups {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\tconsumer, err \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> kafka.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">NewKafkaConsumer\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(brokersUrl, g.group.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">String\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">())\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\tif\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> err \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">!=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\"> nil\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t\tlog.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Fatalf\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"Failed to start \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%s\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%v\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, g.group, err)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\thandler \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> kafka.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">NewConsumerGroupHandler\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(g.handle, g.router, g.delay)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\twg.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Go\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">func\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">() {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\t\tif\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> err \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> consumer.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Run\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(ctx, []\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{g.topic.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">String\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">()}, handler); err \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">!=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\"> nil\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t\t\tlog.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Printf\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%s\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> stopped: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%v\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, g.group, err)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t})\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tengine \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> gin.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Default\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">()\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tv1 \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> engine.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Group\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u002Fapi\u002Fv1\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tapi.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">NewOrderHandler\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(orders).\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Register\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(v1)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tsrv \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> &#x26;\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">http\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Server\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\tAddr:    \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\":8080\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\tHandler: engine,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\tgo\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> func\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">() {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t\tif\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> err \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> srv.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">ListenAndServe\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(); err \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">!=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\"> nil\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> &#x26;&#x26;\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\"> !\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">errors.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Is\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(err, http.ErrServerClosed) {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t\tlog.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Printf\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"HTTP server failed: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%v\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, err)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">\t\t\tstop\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">()\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t}()\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tlog.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Println\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"Server and consumers running\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\t&#x3C;-\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">ctx.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Done\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">()\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tlog.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Println\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"Interruption detected, shutting down gracefully...\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\tshutdownCtx, cancel \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> context.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">WithTimeout\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(context.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Background\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(), \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\">10\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">*\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">time.Second)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\tdefer\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\"> cancel\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">()\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">\tif\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> err \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">:=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> srv.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Shutdown\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(shutdownCtx); err \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#A0A0A0;--shiki-light:#D73A49\">!=\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\"> nil\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t\tlog.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Printf\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"HTTP shutdown: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#005CC5\">%v\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">, err)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">\twg.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Wait\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">()\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Ffigure>\n\u003Cp>So basically:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>We create a Kafka producer, a retry router and our order service. The router gets the list of retry topics and the DLQ, so it knows where a failed message goes next.\u003C\u002Fli>\n\u003Cli>The \u003Ccode>groups\u003C\u002Fcode> table defines every consumer we run. There is one for the \u003Ccode>created\u003C\u002Fcode> topic and one for each retry topic.\u003C\u002Fli>\n\u003Cli>The \u003Ccode>created\u003C\u002Fcode> consumer has no router. That's on purpose. When an order fails, the saga has already rolled it back and scheduled any failed compensations, so there is nothing left to retry. Only compensations go through the retry topics, never orders.\u003C\u002Fli>\n\u003Cli>Each retry consumer has a router and a delay. If a compensation fails again, the router moves it to the next tier, and after the last tier, it goes to the DLQ.\u003C\u002Fli>\n\u003Cli>The topics are named \u003Ccode>retry_1m\u003C\u002Fcode>, \u003Ccode>retry_5m\u003C\u002Fcode> and \u003Ccode>retry_10m\u003C\u002Fcode>, but the delays here are 1, 5 and 10 seconds. I shortened them for the demo, so you don't have to wait 16 minutes to see a message hit the DLQ. In production, you would use the real delays.\u003C\u002Fli>\n\u003Cli>Each consumer runs in its own goroutine using \u003Ccode>wg.Go\u003C\u002Fcode> (this needs Go 1.25 or newer). Then we start the HTTP server and wait for a shutdown signal. When it comes, we stop the server and wait for the consumers to finish.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2>Testing\u003C\u002Fh2>\n\u003Cp>Now, how do we test this?\u003C\u002Fp>\n\u003Cp>First, we need Kafka running. Here is the Docker Compose file for a single node Kafka in KRaft mode:\u003C\u002Fp>\n\u003Cfigure data-rehype-pretty-code-figure=\"\">\u003Cpre tabindex=\"0\" data-language=\"yaml\" data-theme=\"vesper github-light\">\u003Ccode data-language=\"yaml\" data-theme=\"vesper github-light\" style=\"display: grid;\">\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#8B8B8B94;--shiki-light:#6A737D\"># docker-compose.yml\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\"> \u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#22863A\">services\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">:\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#22863A\">  broker\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">:\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#22863A\">    image\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">apache\u002Fkafka:latest\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#22863A\">    hostname\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">broker\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#22863A\">    container_name\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">broker\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#22863A\">    ports\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">:\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">      - \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">9092:9092\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#22863A\">    environment\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">:\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#22863A\">      KAFKA_BROKER_ID\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\">1\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#22863A\">      KAFKA_NODE_ID\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\">1\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#22863A\">      KAFKA_PROCESS_ROLES\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">broker,controller\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#22863A\">      CLUSTER_ID\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">8yPqetQpLSJu3qfIpWnnjQ\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#22863A\">      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT,CONTROLLER:PLAINTEXT\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#22863A\">      KAFKA_LISTENERS\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">PLAINTEXT:\u002F\u002Fbroker:29092,CONTROLLER:\u002F\u002Fbroker:29093,PLAINTEXT_HOST:\u002F\u002F0.0.0.0:9092\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#22863A\">      KAFKA_ADVERTISED_LISTENERS\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">PLAINTEXT:\u002F\u002Fbroker:29092,PLAINTEXT_HOST:\u002F\u002Flocalhost:9092\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#22863A\">      KAFKA_INTER_BROKER_LISTENER_NAME\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">PLAINTEXT\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#22863A\">      KAFKA_CONTROLLER_LISTENER_NAMES\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">CONTROLLER\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#22863A\">      KAFKA_CONTROLLER_QUORUM_VOTERS\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">1@broker:29093\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#22863A\">      KAFKA_LOG_DIRS\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\u002Ftmp\u002Fkraft-combined-logs\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#22863A\">      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\">1\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#22863A\">      KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\">0\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#22863A\">      KAFKA_TRANSACTION_STATE_LOG_MIN_ISR\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\">1\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#22863A\">      KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\">1\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Ffigure>\n\u003Cp>If you want to know what each of these settings does, I explained them in my \u003Ca href=\"\u002Fblog\u002F1f6874d4-270c-48e1-9798-324b494c7f0e\">Kafka pipelines guide\u003C\u002Fa>.\u003C\u002Fp>\n\u003Cp>Start Kafka, then run the server:\u003C\u002Fp>\n\u003Cfigure data-rehype-pretty-code-figure=\"\">\u003Cpre tabindex=\"0\" data-language=\"bash\" data-theme=\"vesper github-light\">\u003Ccode data-language=\"bash\" data-theme=\"vesper github-light\" style=\"display: grid;\">\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">docker\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> compose\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> up\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#005CC5\"> -d\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">go\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> run\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> cmd\u002Fmain.go\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Ffigure>\n\u003Cp>The order endpoint is \u003Ccode>http:\u002F\u002Flocalhost:8080\u002Fapi\u002Fv1\u002Forders\u003C\u002Fcode>. Every request below is a \u003Ccode>POST\u003C\u002Fcode> to that endpoint, and every valid order returns a \u003Ccode>202\u003C\u002Fcode>:\u003C\u002Fp>\n\u003Cfigure data-rehype-pretty-code-figure=\"\">\u003Cpre tabindex=\"0\" data-language=\"json\" data-theme=\"vesper github-light\">\u003Ccode data-language=\"json\" data-theme=\"vesper github-light\" style=\"display: grid;\">\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\">  \"order_id\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"ord_7e840903b59d1253\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\">  \"status\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"PROCESSING\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Ffigure>\n\u003Cp>The response only tells you the order was accepted. To see what actually happened, watch the console where the server is running.\u003C\u002Fp>\n\u003Ch3>The Happy Path\u003C\u002Fh3>\n\u003Cp>Send an order with a total of $400 (2 × $200), which is under our $1000 payment limit:\u003C\u002Fp>\n\u003Cfigure data-rehype-pretty-code-figure=\"\">\u003Cpre tabindex=\"0\" data-language=\"json\" data-theme=\"vesper github-light\">\u003Ccode data-language=\"json\" data-theme=\"vesper github-light\" style=\"display: grid;\">\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\">  \"user_id\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"u1\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\">  \"product_id\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"p1\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\">  \"quantity\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\">2\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\">  \"unit_price\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\">200\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\">  \"shipping_address\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">: {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\">    \"street\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"00, Allen Avenue\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\">    \"city\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"Ikeja\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\">    \"country\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"NG\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">  }\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Ffigure>\n\u003Cp>Every step goes through, and you should see this in the console:\u003C\u002Fp>\n\u003Cfigure data-rehype-pretty-code-figure=\"\">\u003Cpre tabindex=\"0\" data-language=\"bash\" data-theme=\"vesper github-light\">\u003Ccode data-language=\"bash\" data-theme=\"vesper github-light\" style=\"display: grid;\">\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Creating\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> order\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> ord_7e840903b59d1253\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Reserving\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\"> 2\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> units\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> of\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> product\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> p1\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Processing\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> payment\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> of\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> $400\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">.00\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Order\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> ord_7e840903b59d1253\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> completed:\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> [create-order \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">reserve-inventory\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> process-payment]\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Ffigure>\n\u003Ch3>Payment Failure and Rollback\u003C\u002Fh3>\n\u003Cp>Now send an order with a total of $3000 (5 × $600), which is over the payment limit:\u003C\u002Fp>\n\u003Cfigure data-rehype-pretty-code-figure=\"\">\u003Cpre tabindex=\"0\" data-language=\"json\" data-theme=\"vesper github-light\">\u003Ccode data-language=\"json\" data-theme=\"vesper github-light\" style=\"display: grid;\">\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">{\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\">  \"user_id\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"u1\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\">  \"product_id\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"p1\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\">  \"quantity\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\">5\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\">  \"unit_price\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\">600\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\">  \"shipping_address\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">: {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\">    \"street\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"00, Allen Avenue\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\">    \"city\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"Ikeja\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\">    \"country\"\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">: \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">\"NG\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">  }\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">}\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Ffigure>\n\u003Cp>The order is created and the stock is reserved, then the payment gets declined. The saga starts rolling back, but releasing the stock fails because our inventory service is \"down\". The rollback carries on and cancels the order, and the failed release is sent to the first retry topic:\u003C\u002Fp>\n\u003Cfigure data-rehype-pretty-code-figure=\"\">\u003Cpre tabindex=\"0\" data-language=\"bash\" data-theme=\"vesper github-light\">\u003Ccode data-language=\"bash\" data-theme=\"vesper github-light\" style=\"display: grid;\">\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Creating\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> order\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> ord_88dcc49ea1e17837\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Reserving\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\"> 5\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> units\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> of\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> product\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> p1\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Cancelling\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> order\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> ord_88dcc49ea1e17837\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Routing\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> message\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> to\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> topic:\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> retry_1m\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> (Attempt \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#8B8B8B94;--shiki-light:#6A737D\">#1): compensate reserve-inventory: inventory service unavailable (release attempt 1)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Processing\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> failed\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> on\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> topic\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> created:\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> order\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> ord_88dcc49ea1e17837\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> failed\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> at\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> step\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> \"process-payment\":\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> payment\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> of\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> $3000\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">.00\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> declined:\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> insufficient\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> funds\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">; \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">compensation\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> retry\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> scheduled:\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> compensate\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> reserve-inventory:\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> inventory\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> service\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> unavailable\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> (release \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">attempt\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\"> 1\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">)\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Ffigure>\n\u003Cp>A second later, the first retry fails too, and the message moves to the next tier:\u003C\u002Fp>\n\u003Cfigure data-rehype-pretty-code-figure=\"\">\u003Cpre tabindex=\"0\" data-language=\"bash\" data-theme=\"vesper github-light\">\u003Ccode data-language=\"bash\" data-theme=\"vesper github-light\" style=\"display: grid;\">\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Processing\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> failed\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> on\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> topic\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> retry_1m.\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> Routing\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> to\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> next\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> stage...\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Routing\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> message\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> to\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> topic:\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> retry_5m\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> (Attempt \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#8B8B8B94;--shiki-light:#6A737D\">#2): compensate reserve-inventory: inventory service unavailable (release attempt 2)\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Ffigure>\n\u003Cp>Five seconds after that, the inventory service is \"back\", and the release finally works:\u003C\u002Fp>\n\u003Cfigure data-rehype-pretty-code-figure=\"\">\u003Cpre tabindex=\"0\" data-language=\"bash\" data-theme=\"vesper github-light\">\u003Ccode data-language=\"bash\" data-theme=\"vesper github-light\" style=\"display: grid;\">\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Releasing\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\"> 5\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> units\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> of\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> product\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> p1\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> (release \u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\">attempt\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#005CC5\"> 3\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan data-line=\"\">\u003Cspan style=\"--shiki-dark:#FFC799;--shiki-light:#6F42C1\">Order\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> ord_88dcc49ea1e17837\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> rolled\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> back\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> after\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> retrying\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#99FFE4;--shiki-light:#032F62\"> compensations:\u003C\u002Fspan>\u003Cspan style=\"--shiki-dark:#FFF;--shiki-light:#24292E\"> [reserve-inventory]\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Ffigure>\n\u003Cp>The order failed, but the system ended up clean. The stock was released and the order was cancelled. That's eventual consistency in action.\u003C\u002Fp>\n\u003Cp>If you set \u003Ccode>releaseFailures\u003C\u002Fcode> to \u003Ccode>4\u003C\u002Fcode> in \u003Ccode>steps.go\u003C\u002Fcode> and send the same order again, the release fails on every tier and the message ends up in the DLQ. That's where a human steps in to fix it.\u003C\u002Fp>\n\u003Ch3>Bad Requests\u003C\u002Fh3>\n\u003Cp>Lastly, try sending an order with \u003Ccode>\"quantity\": 0\u003C\u002Fcode>, or remove the \u003Ccode>product_id\u003C\u002Fcode> field. Gin rejects it with a \u003Ccode>400\u003C\u002Fcode> before anything reaches Kafka.\u003C\u002Fp>\n\u003Ch2>Demo\u003C\u002Fh2>\n\u003Cp>Here is a demo of how all these concepts come together:\u003C\u002Fp>\n\u003Cp>\u003Cvideo src=\"https:\u002F\u002Fres.cloudinary.com\u002Fdb6nohcui\u002Fvideo\u002Fupload\u002Fq_auto,f_auto\u002Fv1792379313\u002Fportfiolio-blog\u002Fo6mhc1aiyv4nuq5goiex.mp4\" controls playsinline preload=\"metadata\">\u003C\u002Fvideo>\u003C\u002Fp>\n\u003Ch2>Conclusion\u003C\u002Fh2>\n\u003Cp>In this guide, we built an orchestrated saga in Go that keeps an order consistent across the order, inventory and payment services. The key takeaways are:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>ACID transactions work great inside one database, but they can't span multiple microservices, each with its own database.\u003C\u002Fli>\n\u003Cli>The saga pattern splits a business transaction into local transactions, each with a compensating transaction that undoes it.\u003C\u002Fli>\n\u003Cli>When a step fails, the completed steps are undone in reverse order, and the failed step itself is not compensated.\u003C\u002Fli>\n\u003Cli>A step that fails because of a business rule (like a declined payment) is a finished outcome, not something to retry.\u003C\u002Fli>\n\u003Cli>A compensation that fails is the dangerous case, because it leaves the system half rolled back. Retry topics give it time to recover, and a DLQ catches the ones that never do.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>The saga pattern maintains eventual consistency without distributed locks, and each service can use its own database and transaction model. But it does come with trade-offs:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>Only eventual consistency\u003C\u002Fstrong>: Intermediate states are visible to other processes. For a short time, someone could see a reserved stock for an order that is about to be cancelled.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>More code to maintain\u003C\u002Fstrong>: Every step needs a compensation, and that compensation has to be maintained alongside the forward logic. Some operations, like sending an email, can't really be undone at all.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Idempotency\u003C\u002Fstrong>: Retries can run a compensation more than once, so your compensations must be idempotent. Releasing the same stock twice should not release double the stock.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Lack of isolation\u003C\u002Fstrong>: The \"I\" in ACID is gone. Multiple sagas running at the same time can read and change the same data, which can cause data anomalies. A common fix is a semantic lock, like marking the order as \u003Ccode>PROCESSING\u003C\u002Fcode> while its saga runs, so other processes know not to trust it yet.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>(If you want to see the full codebase, check out the \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fumohsamuel\u002Fdistributed-transactions\">repository\u003C\u002Fa>. Play around with it and lmk what you think)\u003C\u002Fp>\n\u003Ch2>References\u003C\u002Fh2>\n\u003Cul>\n\u003Cli>\u003Ca href=\"https:\u002F\u002Fwww.databricks.com\u002Fblog\u002Fwhat-are-acid-transactions\">Databricks: What are ACID Transactions?\u003C\u002Fa>\u003C\u002Fli>\n\u003Cli>\u003Ca href=\"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FDistributed_transaction\">Wikipedia: Distributed Transaction\u003C\u002Fa>\u003C\u002Fli>\n\u003Cli>\u003Ca href=\"https:\u002F\u002Fmicroservices.io\u002Fpatterns\u002Fdata\u002Fsaga.html\">Microservices.io: Pattern: Saga\u003C\u002Fa>\u003C\u002Fli>\n\u003Cli>\u003Ca href=\"https:\u002F\u002Foneuptime.com\u002Fblog\u002Fpost\u002F2026-01-25-saga-pattern-distributed-transactions-go\u002Fview\">OneUptime: How to Implement the Saga Pattern for Distributed Transactions in Go\u003C\u002Fa>\u003C\u002Fli>\n\u003C\u002Ful>","October 19, 2026","2026-10-19T03:14:02.521Z"]