Hello! Welcome back to our module on Distributed Transactions.
In our last lesson, we designed a complete saga flow on paper, carefully mapping out the forward transactions for the "happy path" and the compensating transactions for handling failures. We also identified the critical pivot transaction that marks the point of no return.
Today, we transition from design to practice. Your learning outcome is to implement a choreographed saga using events for the 'happy path' and compensating transactions. We will translate the abstract flow we designed into concrete Spring Boot services that communicate asynchronously using a message broker. This is a very common interview topic, as it tests your ability to write resilient, loosely coupled systems.
1. From Design to Choreography
In the choreography pattern, there is no central controller. Instead, each service in the saga performs its local transaction and then publishes an event. Other services subscribe to these events and react accordingly. The entire business process unfolds as a chain reaction of events.
The "happy path" is driven by success events (e.g., OrderCreated, PaymentProcessed), while the failure path is driven by failure events (e.g., InventoryFailed), which trigger compensating actions in services that have already completed their part of the saga.
Let's visualize the "happy path" first.

Now, let's visualize how compensating transactions fit in.

To implement this, each service will need to:
- Perform its own atomic, local database transaction.
- Publish an event to a message broker (we'll use Kafka) to signal completion or failure.
- Listen for events from other services to know when to act.
2. Implementing the Choreographed Saga: An E-commerce Example
We will now walk through a complete implementation of a choreographed saga for an e-commerce order flow. The system will consist of four services: OrderService, PaymentService, InventoryService, and ShippingService.
The following resource provides a full, end-to-end implementation using Spring Boot and Kafka. We will use it as our guide. I will not ask you to read the entire article at once, but rather refer you to specific sections as we build up the saga step-by-step.
Implementing Choreography and Orchestration-Based Saga Patterns in Spring Boot
First, let's understand the scenario and the common project setup. This article, "Implementing Choreography and Orchestration-Based Saga Patterns in Spring Boot," will be our primary reference. Familiarize yourself with the overall flow.
Read the sections "Practical Considerations", "Scenario", and "Step-by-Step Implementation" up to (but not including) "Step 4: Order Service Implementation". Focus on understanding the four services involved, the overall sequence of events, and the common Maven and application.properties configurations for Kafka integration.
As you've seen, each service is a standard Spring Boot application with dependencies for Web, JPA, and Kafka. The key Kafka properties in application.properties configure the connection to the broker and the serializers for sending/receiving events as JSON.
Now, let's implement each service's logic, starting with the one that kicks off the saga.
3. The Happy Path: Forward Transactions
Step 1: Order Service - Initiating the Saga
The OrderService starts the process. It receives a request to create an order, saves the order to its own database in a CREATED state, and then publishes an OrderCreatedEvent.
Implementing Choreography and Orchestration-Based Saga Patterns in Spring Boot
Let's examine the implementation of the OrderService. Pay close attention to how the createOrder method both saves the local entity and publishes an event using KafkaTemplate.
Read "Step 4: Order Service Implementation". Study the OrderService.java class. Notice the kafkaTemplate.send("order-topic", event); line. This is the core of its role in the choreography.
Step 2: Payment Service - Reacting to the First Event
The PaymentService is the next participant. It doesn't have a REST controller to start its process. Instead, it listens for the OrderCreatedEvent on the order-topic. When it receives the event, it processes the payment and publishes its own event, PaymentProcessedEvent, to the payment-processed-topic.
Implementing Choreography and Orchestration-Based Saga Patterns in Spring Boot
Now, let's see how the PaymentService continues the chain. The key component here is the @KafkaListener annotation, which turns a method into an event consumer.
Read "Step 5: Payment Service Implementation". In PaymentService.java, focus on the processPayment method. See how it is triggered by @KafkaListener(topics = "order-topic") and how it publishes a new event to payment-processed-topic upon success.
Step 3: Inventory and Shipping Services - Completing the Saga
The pattern continues:
- The Inventory Service listens for
PaymentProcessedEvent, reserves stock, and publishesInventoryReservedEvent. - The Shipping Service listens for
InventoryReservedEventand schedules the shipment, which is the final step in our happy path.
You can review their implementations following the same logic.
Implementing Choreography and Orchestration-Based Saga Patterns in Spring Boot
To complete the picture, quickly review the InventoryService and ShippingService. They follow the exact same pattern of listening for an event and acting on it.
Read "Step 6: Inventory Service Implementation" and "Step 7: Shipping Service Implementation". Confirm your understanding of how each service is triggered by an event from the previous step.
4. The Failure Path: Implementing Compensating Transactions
A saga is only robust if it can handle failures. In choreography, this is achieved by publishing failure events and having other services listen for them to execute their compensating logic.
Let's see this in action. The provided example simulates a failure in the InventoryService (e.g., item is out of stock). When this happens, it publishes an InventoryFailedEvent.
Now, the services that came before it must undo their work.
- The Payment Service must refund the payment.
- The Order Service must cancel the order.
How is this implemented? By adding another @KafkaListener in each of those services that subscribes to the inventory-failed-topic.
Let's look back at the code for the PaymentService and OrderService to see how they handle compensation.
- In
PaymentService.java(from section 5 of the resource), you'll find therefundPaymentmethod, annotated with@KafkaListener(topics = "inventory-failed-topic"). When it receives a message on this topic, it finds the payment and updates its status toREFUNDED. - Similarly, in
OrderService.java(from section 4), thehandleInventoryFailedmethod listens to the same topic and updates the order's status toCANCELLED.
This is the choreography pattern in its entirety: services react not only to success events that move the saga forward, but also to failure events that move it backward, ensuring the system remains consistent.
Test your understanding!
Imagine your e-commerce platform becomes more popular, and you need to add a LoyaltyService. After the PaymentService successfully processes a payment, it should notify the LoyaltyService to award points to the customer.
However, the LoyaltyService can fail if the customer's account is suspended. If this happens, it publishes a PointsAwardFailedEvent.
Which service(s) need to be modified to handle this failure, and what logic would you add?
Show answer
This is a classic interview question to check if you can extend an existing pattern. The failure in the LoyaltyService occurs after payment has been taken, so we must roll back the entire transaction.
-
PaymentService Modification:
- It must subscribe to the
points-award-failed-topic. - You would add a new method, annotated with
@KafkaListener(topics = "points-award-failed-topic"), that contains the compensation logic: refunding the payment. This logic would be very similar to the existingrefundPaymentmethod.
- It must subscribe to the
-
OrderService Modification:
- It must also subscribe to the
points-award-failed-topic. - You would add a method with a
@KafkaListenerthat cancels the order, similar to thehandleInventoryFailedmethod.
- It must also subscribe to the
The InventoryService and ShippingService would not be involved, as the failure occurs before they are ever triggered.
5. Running and Testing the Saga
To see this system in action, you would:
- Start a Kafka instance (and Zookeeper).
- Create the required topics:
order-topic,payment-processed-topic,inventory-reserved-topic,inventory-failed-topic, etc. - Run all four Spring Boot applications.
- Send a POST request to the
OrderService's/ordersendpoint.
By observing the logs of each service and the status changes in their respective databases, you can trace the flow of events for both a successful transaction and a failed one. The resource LINK explains how to trigger both scenarios in its "Step 8: Running the System" section.
Conclusion
In this lesson, we translated our theoretical saga design into a working, event-driven system using Spring Boot and Kafka. This hands-on implementation is crucial for internalizing the pattern and discussing it confidently in an interview.
Key Takeaways:
- Choreography is decentralized: Services operate independently, reacting to events.
- Events drive the flow: Both forward progress (happy path) and rollbacks (compensation) are triggered by events.
- Implementation relies on:
- A message broker like Kafka or RabbitMQ.
KafkaTemplate(or similar) to publish events.@KafkaListener(or similar) to consume events.
- Compensation is just more event handling: A service that needs to compensate for a failure simply subscribes to the relevant failure event topic.
Next Up
While choreography offers great loose coupling, its decentralized nature can make it difficult to monitor and debug the end-to-end business process. Where did the transaction fail? Which services were involved? An alternative approach addresses these challenges.
In the next lesson, we will implement the exact same e-commerce saga, but this time using the orchestration pattern. You will create a central orchestrator service that explicitly commands each participant, providing a clear point of control and observability. This will give you a powerful comparison of the two main saga implementation strategies.
Can't find a good explanation? Sign up and we'll make it for you
Sign up