← все видео

Saga Design Pattern in Microservices Spring Boot | Food Delivery Example

codippa · 2026-05-15 · 22м 24с · 116 просмотров · YouTube ↗

Топики: durable-execution

🎧 Аудио

📝 Summary

model=deepseek-v4-flash · prompt=summary-v7 · 5 211→1 742 tokens · 2026-07-20 15:09:53

🎯 Главная суть

При заказе еды через Swiggy или Zomato задействованы десятки микросервисов — заказы, платежи, рестораны, доставка. Если платёж прошёл, а ресторан отклонил заказ, или доставка провалилась, глобальный откат невозможен — нет единой транзакции. Паттерн Saga разбивает эту длинную операцию на цепочку локальных транзакций, каждая из которых фиксируется независимо. При сбое выполняются компенсирующие действия (возврат платежа, отмена заказа) вместо автоматического отката.

Проблема распределённых транзакций в микросервисах

В онлайн-заказе еды участвуют Order Service, Payment Service, Restaurant Service, Delivery Service. Каждый сервис — отдельный процесс, управляющий своей БД. Невозможно обернуть всю операцию в одну ACID-транзакцию: не существует глобального менеджера, который мог бы откатить все изменения одновременно. Если платёж успешно списался, а ресторан отклонил заказ, система оказывается в несогласованном состоянии — деньги ушли, еда не приготовлена. Паттерн Saga предлагает вместо этого выполнять каждый шаг как отдельную транзакцию, а при ошибке запускать явные компенсирующие транзакции: для описанного случая — refund платежа и cancel заказа.

Два стиля реализации Saga

Choreography (хореография) — децентрализованный подход без контроллера. Каждый сервис реагирует на события и генерирует следующие. Например: Order Service публикует событие OrderCreated → Payment Service слушает, обрабатывает платёж, публикует PaymentSuccess → Restaurant Service слушает и т.д. Это гибкая архитектура, но при сбоях сложно отслеживать цепочку — приходится трассировать все события.

Orchestration (оркестрация) — вводится центральный координатор (Orchestrator), который последовательно вызывает сервисы и явно обрабатывает ошибки. Если на каком-то шаге возникло исключение, оркестратор сразу запускает компенсирующие действия (например, возврат платежа). Проще отлаживать, так как вся логика сосредоточена в одном классе, но возникает жёсткая связность.

Реализация оркестрации на Spring Boot (демонстрация)

Для упрощения все сервисы реализованы внутри одного приложения: каждый класс (PaymentService, RestaurantService) имитирует микросервис.
SagaOrchestrator получает OrderCreateRequest (поле orderId + флаг orderConfirmed).

Создан REST-контроллер с POST-эндпоинтом /orders. При тестировании через Postman отправляется JSON с orderId и orderConfirmed. Если true — консоль показывает «Payment processed, order confirmed». Если false — после исключения выводится «Payment processed, refund initiated». Управление сбоем сводится к одному булевому флагу, что упрощает тестирование обоих сценариев.

Реализация хореографии на Spring Boot (демонстрация)

Здесь используется встроенный механизм событий Spring: ApplicationEventPublisher для публикации событий, @EventListener для обработчиков.
Созданы три класса событий: OrderCreatedEvent, PaymentSuccessEvent, OrderFailedEvent — каждый содержит поле OrderCreateRequest.
Сервисы-слушатели:

Контроллер ChoreographyController (POST /orders-choreography) просто публикует OrderCreatedEvent и сразу возвращает ответ «Order initiated» — не дожидаясь полного завершения. При тестировании: первый запрос (orderConfirmed=true) даёт логи «Payment processed» → «Order accepted»; второй (orderConfirmed=false) → «Payment refunded». Никакого центрального оркестратора — каждый слушатель реагирует только на свои события.

Сравнение подходов: когда что использовать

Оркестрация — лучший выбор для начинающих: линейный поток, легко проследить, отладить, добавить новые шаги. Плата — жёсткая связность: оркестратор знает о всех сервисах.
Хореография — подходит для крупных систем, где требуется масштабирование и слабая связность. Сервисы общаются через события, новые участники могут подключаться, не изменяя существующий код. Недостаток: сложная трассировка сбоев — чтобы понять причину, нужно восстанавливать всю цепочку событий. При старте проектов чаще выбирают оркестрацию, для высоконагруженных распределённых систем — хореографию.

📜 Transcript

en · 2 805 слов · 41 сегментов · clean

Показать текст транскрипта
ordering food online seems simple right you click order payment goes through food arrives but behind the scenes many distributed systems work and there are many scenarios to be handled what if your payment succeeds but the restaurant rejects the order or worse delivery fails after your money is deducted that's not a bug that's a distributed transaction problem And companies like Swiggy and Zomato solve this using something called the Saga pattern. When you place an order, multiple services are involved. Order service, payment service, restaurant service, delivery service, and so on. Each one runs independently, which means we cannot wrap everything in a single transaction. There is no global rollback. So if something fails in between, the system becomes inconsistent. Let's understand this practically. Here is the normal flow for food or drink system. First, order is created, then payment is deducted, then restaurant accepts, and finally delivery is assigned. Consider one failure flow, where restaurant rejects order. Now what? This is exactly the problem saga pattern solves. Saga pattern breaks one big transaction into multiple small ones. Each step is completed independently. And if something fails, we don't roll back automatically. We execute compensating transactions. So, instead of undoing everything, we manually reverse each completed step. So, the compensation steps or actions for this case will be to refund payment and cancel the order. There are two implementation styles for saga pattern. First is choreography or event driven. In choreography there is no central controller. Each service reacts to events and triggers the next step. Order service emits an event. Payment service listens and processes it and then emits another event. Restaurant service listens next and so on. It is fully decentralized which makes it more flexible. but also harder to trace when something goes wrong. Second is orchestration. In orchestration, we introduce a central controller. This orchestrator controls the entire flow. It calls each service step by step and handles failures explicitly. This makes debugging easier because all logic is in one place. We will understand Saga implementation practically using Spring Boot, and go through both these implementations one by one and step by step let's first start with orchestration style saga implementation a quick clarification before we jump into code in real systems order payment restaurant and delivery are separate micro services but for this demo we will be implementing everything inside a single spring boot application why because the goal is to understand the saga flow not deal with infrastructure complexity like multiple services, networking, and deployment. So think of each class, payment service, restaurant service, as an independent microservice simulation. Let's begin. This is a Spring Boot application having just a main class. The dependency that we have added is only Spring Web, and the build tool is Gradle with Java 24. Let's add a new class which will be the Orchestrator. Name it Saga Orchestrator. Add a method called StartSaga, which will be the controlling point for SagaPattern. This method will be called from the controller and should receive some details about the order, such as OrderId and if the restaurant has accepted the order or not. Define a new class which will be the OrderCreateRequest. Its object will have the order details and it will be shared across all services. Create fields for OrderId. and a boolean indicating if the restaurant has accepted the order. In real system, this object can have many fields such as address, payment mode details, delivery time, etc. Generate getters and setters. Back to orchestrator class. Add order create request object as a parameter. Now, this orchestrator is responsible for processing payment and confirming order. If the order is not confirmed, then execute a compensating action which will be able to reverse payment. Let's create a new payment service class that will be responsible for processing payments. Add a process payment method. Again, this will accept an object of OrderCreateRequest. Print a message for this order ID. Add a new method for reversing payment. This will also take OrderCreateRequest object. Print a message. Add service annotation over this class to make it a spring service. Next add a new service for restaurant, which will have restaurant-related operations. Add a service annotation. Define a method confirmOrder, which also has an OrderCreateRequest object as a parameter. Check if the order is confirmed. Then print message. Else throw an exception. Note that in a real application, this method will decide if the order is to be confirmed or not. Since we are using only one service, and for testing purpose we need to send a flag from the request object only. This will simplify testing both positive and negative scenarios. Finally, stitch all this together in orchestrator. Make the orchestrator as a service by adding annotation. Inject payment and order services using auto-wired annotation. Now, Process payment for this order. Then check if the order is confirmed. Surround this method call in an exception block to reverse payment if the restaurant rejects the order. Finally, call refund payment method from catch block. Now let's create a controller class so that we can expose an API endpoint. Address controller and request mapping annotations to make it a spring controller and for defining an endpoint. We can provide base URL after request mapping annotation. Inject orchestrator service by auto wiring it here. Define a method to create order. Since this method will be creating a resource, it should be post request and hence we need to use a post mapping. The method will return a response entity and will accept an order create request object. The object will be populated from the request itself. So it should have a request body annotation. Call start saga method from orchestrator service and return the result. There is a compiler error. Let's check the reason. Okay. We need to change the start saga method to return a result instead of void. Let's return messages for success and error. Back to controller. Create an object of response entity using its static ok method. Which returns the string message and an HTTP 200 response code which stands for successful execution. Let's test the implementation now. Start the application. It is started at port 8080 Open Postman Create a new request of type http The base URL will be localhost colon 8080 We have mapped an endpoint slash orders Method is of type post Accepting a request body with these two fields So add orders URL Request will be of type post To send request body click here Set it to raw And its type will be JSON. Add fields for order ID with some random alphanumeric value. And order confirmed as true. This will be a happy path where the order goes smooth. Click send. Order is successful. Let's check console messages. Payment processed and order confirmed. Now set order confirmed to false to check the scenario where restaurant rejects order. Send. Order failed is the response we get. Go back to see the messages. Payment processed and then refund it. Notice how I can control failure using a simple boolean. If restaurant fails, orchestrator immediately triggers refund. This is saga with centralized control. In a real application, the order id should also be generated at the backend rather than sending it from the client. Let's understand the choreography based saga pattern. In this pattern, instead of direct communication, we have an event for everything. So, we will have an event for order created, payment success and order failed. For each event, there are listeners which listen for an event. These listeners act upon when the event on which they are listening is emitted. After processing, these listeners emit subsequent events. So, if we look at our application, when an order is created, we need a payment listener which processes payment and then emits payment success. This event is then listened by a restaurant listener which checks if the order is confirmed. If not, then order failed event is emitted. So, now we need a listener which listens for order failed event and processes a refund. I guess you got a basic idea how event and listeners work. For Spring Boot implementation, we will use its native event listening framework. where there is an ApplicationEventPublisher interface which has a method called PublishEvent. This method accepts an object which represents the event that is published. Let's say OrderCreatedEvent. So, whenever or from wherever you want to emit an event, inject ApplicationEventPublisher object and call its PublishEvent method. Now, in order to listen to an event, simply create a method with an event object as argument. and add an event listener annotation. Doing these two steps informs Spring Boot that whenever an event of this argument type is published from within the application, this handler method will be called. There are already some videos on Spring event handling framework on this channel. You can check them out. Let us now implement choreography-based saga pattern in Spring Boot. First, we will create event classes which are required for this. First is an order created event. Let's place it in an event package for better separation. Every event object should have the order create request that is received through the controller. So that the listener which will listen to this event has all the details related to the order. Generate getters and setters. You can also avoid the setter method and accept the request object as a constructor argument. Next create an order failed event. Again, include the order create request field and it scatters setters methods. This event will be emitted by the restaurant listener when the order is not confirmed. Next event will be payment success. Add the same order create request and it scatters setters. This event will be emitted when the order is first received and the payment is successful. All the events are created. Now start creating listeners. First will be payment listener. This listener will come into picture when the order is first placed that is just after the request arrives at the controller This listener will process payment and then emit payment success event As I stated earlier in order to emit an event we need application event publisher and every listener must have it So declare a field of type application event publisher inject its object using constructor injection Next, define a method to handle the event. This method must accept the object of the event type that it will be listening to. For payment listener, the event will be order created. Print a message for payment processed. Publish a payment success event for the next listener to pick it up and do further processing. For publishing, use publish event method of application event publisher object. Publish event needs an object of the event that you wish to emit. Create the object of payment success event. Set the order create request object in it. You can get this request from the order create event received by this listener since we are setting it in every event. Pass it to the publish event. Finally, in order that this listener method reacts to order created event, we need to add event listener annotation over it to inform Spring Boot that this method is listening to an event. Now you must have understood that whenever order created event will be emitted by any other listener, this method will be called automatically. Also, we need to register this listener class as a spring bean. This we can do by adding a component annotation over it. Time to write another listener. This will be restaurant listener. This will listen to payment success event and will come into picture when payment is successfully completed. The spring bean. inject an object of application event publisher since this listener also needs to emit an event inject its object using constructor injection add an event handler method this method will listen for payment success event which is emitted by payment listener class that we just created check if the order is confirmed then print the message this order confirmed flag we were sending in the request payload and we can get the request object directly from the event If the order is not confirmed, emit OrderFailedEvent. Create an object of OrderFailedEvent. Set the request object in it. And use the publisher to publish this event as we did earlier. If you remember, in orchestrator-based pattern, we were throwing an exception if the order was not confirmed. In choreography, we are emitting an event which will be listened by another listener and handle it accordingly. If in future, we need to change the handling action, such as instead of refunding directly to account we need to refund to some wallet etc then the only change will be at that listener which means that we have decoupled operations while in orchestrator the modification will be at the core implementation add event listener annotation to make this method react to payment success event finally create a new listener that will listen to order failed event make it a spring bean by using component annotation Since this listener is not required to emit any further event, there is no need to inject an application event publisher object. We will just add a handleEvent method which will listen for orderFailedEvent. Print a message that it will be refunding the payment receive for the failed order ID. Add eventListener annotation so that it is able to listen to orderFailedEvent. Next, create a controller to have a separate API endpoint for ChoreographyController. Add REST controller and request mapping annotations. Modify the base URL which is different from the slash orders URL that we used for orchestrator pattern. Now, this controller will receive a request to initiate an order and it has to emit an event of type order created which will be listened by payment listener. Since this controller will emit an event, we need an application event publisher for publishing it. Inject it through the constructor. Add a handler method to handle incoming HTTP request. This will be a post request. It will return a response entity and receive an order create request. Define a new order created event to be listened by the payment listener. Set the incoming request in this event and publish it. Return a response entity object with a message that order creation is initiated. This method will simply emit the event and return response to the client. without holding back the thread this is the principle that reactive programming works on just to recap since there has been a lot of information in this controller we are creating an order created event when this event will be published it will go to its listener which is payment listener listening for this event and we have declared it here this is creating a payment success event when it is published it will go to the restaurant listener which is listening for payment success declared here and this listener will emit order failed event which will be listened by the compensation listener this is configured with this declaration let's test the implementation start the application go back to postman copy this request body since it is the same for choreography pattern as well create a new request modify the url that we configured in choreography controller request will be of type post click on body raw and its type will be json paste the request body click send we get the order initiated response let's check the application logs we are getting order idea as null which means that it is not being populated from the request let's check the controller oh we missed to add request body annotation to the controller method parameter Without this, the request fields will not be mapped to this object. Restart the application. Send the request again. We get the payment processed and order accepted messages. Now set the order confirmed to false. Send. We get the payment refund message. Now notice there is no orchestrator. Each service reacts to events. Failure triggers another event which triggers compensation. Let's compare what we just built. In orchestration, we have one central control. It's easy to follow and debug. But as I said earlier, the logic is tightly coupled. In choreography, there is no central control. It is fully event-driven. Since there is decoupling, it becomes highly scalable. At the same time, any errors are harder to trace since the flow is not linear but reactive. You need to trace events to reach to the root cause. If you are starting out, orchestration is your best friend. If you are building large-scale systems, choreography becomes powerful. Hope you liked the video and learnt about Saga Pattern. Stay tuned for the next microservice pattern explained practically.

⚙️ Pipeline jobs

StageStatusAtt.UpdatedError
download done 1/3 2026-07-20 15:09:15
transcribe done 1/3 2026-07-20 15:09:36
summarize done 1/3 2026-07-20 15:09:53
embed done 1/3 2026-07-20 15:09:55

📄 Описание YouTube

Показать
Learn Saga Pattern in Microservices using a real food delivery example inspired by Swiggy and Zomato. 

In this video, we build both Orchestration and Choreography based Saga Design Pattern in Microservices using Spring Boot with complete runnable code examples.

Understand how distributed transactions work in microservices, how compensating transactions solve failures, and why event driven architecture is essential for scalable systems.

We also compare Saga Orchestration vs Choreography, simulate success and failure scenarios, and execute the APIs live using Postman.

Topics Covered:
✔ Saga Design Pattern in Microservices
✔ Saga Pattern Microservices Spring Boot
✔ Distributed Transactions
✔ Event Driven Architecture
✔ Orchestration vs Choreography
✔ Compensating Transactions
✔ Microservices Design Pattern
✔ Spring Boot Microservices

0:00 Scenario
0:35 Saga Pattern
2:01 Saga Pattern Types
3:42 Orchestration Implementation
10:21 Choreography Implementation
21:33 Comparison
22:06 Conclusion



#springboot #microservices #microservicesarchitecture #spring #springframework #javadeveloper #java #javaprogramming #javaprogrammer #javadevelopment #distributedsystems #designpatterns #saga