#development #elixir #reading-list

🔗 The Saga Pattern in Elixir
peterullrich.com

If you build software long enough, you will eventually encounter use cases that require multiple steps to succeed before the overall process can be considered "complete". If any of the steps fail, you'll want to abort any further steps, roll back the state, and inform someone about the failure. So, either all steps succeed or none do. This is called an atomic transaction, and guaranteeing this Atomicity is harder than you'd expect.

For most use cases, wrapping the steps in a single Ecto.Multi transaction is enough to guarantee Atomicity. If a step fails, Ecto rolls back all database transactions and returns an error. Usually, you'll pass back the error message and let the caller handle it. However, sometimes you might encounter use cases in which you can't wrap all steps in a single transaction. Usually, they include steps that are separated either by time or space.

For example, if a customer rents a car through your software, you might want to mark the order as "pending" until you get the confirmation from your garage that the requested car is indeed available. If the car isn't available, you shouldn't charge the customer's credit card and inform them that they have to pick another car or cancel the order. You couldn't keep the database transaction open until you hear back from the garage, possibly hours or days later. This is an example of a use case separated by "time".

For another example, imagine that if a customer rents a luxury car, you reserve the car with another car rental provider through an API call because you don't own such cars yourself. You decide to reserve the car even before you charge the customer's credit card because you want to avoid the embarrassment that your high-profile customer doesn't get the car although they've just paid for it. But this means that you'll need to cancel the car reservation if the payment fails. Since the reservation record lives in the other car rental's database, you can't wrap it in your transaction and have to call their API again to cancel the reservation. This is an example of a use-case separated by "space".

In both situations, you could resolve the error cases manually. Just expose a "cancel order" button in the UI which refunds all payments and cancels the reservation and let the support employee click it whenever necessary. However, we are software engineers and automating this stuff is our job. So, let's see how we could do that using the Saga pattern.

continue reading on peterullrich.com

⚠️ This post links to an external website. ⚠️