🔥 Launch Offer: Interview Preparation Bundle @ ₹2,499 ₹9,999 • 75% OFF. Offer expires in 🔥 Launch Offer: Interview Preparation Bundle @ ₹2,499 ₹9,999 • 75% OFF. Offer expires in Interview Preparation Bundle @ ₹2,499 ₹9,999

00:00:00 Get Bundle
home microservice saga-pattern-using-orchestration-in-spring-boot-complete-guide-with-real-world-example
Interview guide Microservice 22 sections

Saga Pattern using Orchestration in Spring Boot | Complete Guide with Real-World Example

If you're preparing for Oracle, Walmart, Microsoft, Amazon, Uber, or other product-based company interviews, understanding the Orchestration Saga Pattern is extremely important. Unlike the Choreography Saga, where services…

Start reading
By javainterviewprep June 12, 2026 6 min read

If you’re preparing for Oracle, Walmart, Microsoft, Amazon, Uber, or other product-based company interviews, understanding the Orchestration Saga Pattern is extremely important.

Unlike the Choreography Saga, where services communicate by publishing events, the Orchestration Saga introduces a central coordinator called the Saga Orchestrator.

The orchestrator is responsible for:

  • Calling each microservice
  • Deciding what happens next
  • Handling failures
  • Triggering compensating transactions (rollback)

This makes the workflow much easier to understand and debug.

In this article we’ll build a complete Spring Boot implementation using REST APIs.


Why Do We Need Orchestration?

Imagine an ecommerce application.

A customer places an order.

To complete that order, multiple microservices must execute successfully.

  • Order Service
  • Inventory Service
  • Payment Service
  • Shipping Service

If any service fails, previously completed services must undo their work.

Without an orchestrator, every service would need to know which events to listen to and what to publish.

As the number of services grows, the workflow becomes difficult to understand.

Instead, we introduce one service whose only responsibility is coordinating the saga.


Our Use Case

Customer places an order.

There are five services.

  • Saga Orchestrator
  • Order Service
  • Inventory Service
  • Payment Service
  • Shipping Service

Overall Flow

Client
|
â–¼
Saga Orchestrator
|
â–¼
Order Service
(Create Order)
|
Success
â–¼
Inventory Service
(Reserve Inventory)
|
Success
â–¼
Payment Service
(Process Payment)
|
Success
â–¼
Shipping Service
(Create Shipment)
|
Success
â–¼
Order Service
(Mark Completed)

Notice something important.

Every service only communicates with the Saga Orchestrator.

No service calls another service.


Failure Flow

Suppose payment fails.

Saga Orchestrator

|
â–¼
Order Created

|
â–¼
Inventory Reserved

|
â–¼
Payment Failed

|
â–¼
Call Inventory Compensation

Release Inventory

|
â–¼
Call Order Compensation

Cancel Order

The orchestrator decides every rollback.


Architecture

                 Client
|
â–¼
Saga Orchestrator
_________|_____|__________
| | | |
â–¼ â–¼ â–¼ â–¼
Order Inventory Payment Shipping
Service Service Service Service

Everything passes through the orchestrator.


Step 1

Client sends request

POST /orders

to

Saga Orchestrator

Order Request

public class OrderRequest {

private Long productId;
private int quantity;
private double amount;

}

Response Objects

Each service returns

public class ServiceResponse {

private boolean success;
private String message;

}

Instead of publishing Kafka events, services simply return success or failure.


Order Service

POST /orders
@PostMapping
public Order createOrder(
@RequestBody OrderRequest request){

Order order = new Order();

order.setStatus("CREATED");

repository.save(order);

return order;
}

Compensation API

DELETE /orders/{id}
@DeleteMapping("/{id}")
public void cancelOrder(
@PathVariable Long id){

Order order =
repository.findById(id).get();

order.setStatus("CANCELLED");

repository.save(order);
}

Notice

Order Service exposes two APIs.

  • Business API
  • Compensation API

Inventory Service

Reserve inventory

@PostMapping("/reserve")
public ServiceResponse reserveInventory(
@RequestBody InventoryRequest request){

Product product =
repository.findById(request.getProductId()).get();

if(product.getQuantity()
< request.getQuantity()){

return new ServiceResponse(false,
"Stock unavailable");
}

product.setQuantity(
product.getQuantity()-request.getQuantity());

repository.save(product);

return new ServiceResponse(true,
"Reserved");
}

Compensation

@PostMapping("/release")
public void releaseInventory(
@RequestBody InventoryRequest request){

Product product =
repository.findById(request.getProductId()).get();

product.setQuantity(
product.getQuantity()+request.getQuantity());

repository.save(product);
}

Payment Service

@PostMapping("/pay")
public ServiceResponse pay(
@RequestBody PaymentRequest request){

try{

paymentGateway.pay();

return new ServiceResponse(
true,
"Payment Successful");

}
catch(Exception e){

return new ServiceResponse(
false,
"Payment Failed");
}

}

Shipping Service

@PostMapping("/ship")
public ServiceResponse createShipment(
@RequestBody ShipmentRequest request){

Shipment shipment = new Shipment();

repository.save(shipment);

return new ServiceResponse(
true,
"Shipment Created");
}

Saga Orchestrator

This is the heart of the entire workflow.

@Service
public class OrderSagaOrchestrator {

@Autowired
private OrderClient orderClient;

@Autowired
private InventoryClient inventoryClient;

@Autowired
private PaymentClient paymentClient;

@Autowired
private ShippingClient shippingClient;

public void execute(OrderRequest request){

Order order =
orderClient.createOrder(request);

ServiceResponse inventory =
inventoryClient.reserve(request);

if(!inventory.isSuccess()){

orderClient.cancel(order.getId());

return;
}

ServiceResponse payment =
paymentClient.pay(request);

if(!payment.isSuccess()){

inventoryClient.release(request);

orderClient.cancel(order.getId());

return;
}

ServiceResponse shipping =
shippingClient.ship(request);

if(!shipping.isSuccess()){

paymentClient.refund(order.getId());

inventoryClient.release(request);

orderClient.cancel(order.getId());

return;
}

orderClient.complete(order.getId());

}

}

Notice something very important.

The orchestrator contains the entire business workflow.

Every decision is taken here.


Success Flow

Create Order

↓

Reserve Inventory

↓

Process Payment

↓

Create Shipment

↓

Complete Order

Payment Failure

Create Order

↓

Reserve Inventory

↓

Payment Failed

↓

Release Inventory

↓

Cancel Order

Shipping Failure

Create Order

↓

Reserve Inventory

↓

Payment Success

↓

Shipping Failed

↓

Refund Payment

↓

Release Inventory

↓

Cancel Order

Notice how compensation happens in reverse order of successful operations.


Why Is It Called Orchestration?

Think of an orchestra.

There is one conductor standing in front of the musicians.

The conductor tells:

  • Who starts.
  • Who stops.
  • Who plays next.

Musicians don’t communicate with each other.

They simply follow the conductor.

The Saga Orchestrator works exactly like that.

  • It tells Inventory Service when to reserve stock.
  • It tells Payment Service when to charge the customer.
  • It tells Shipping Service when to create a shipment.
  • It decides when to execute rollback.

Advantages

  • Easy to understand
  • Easy debugging
  • Centralized business logic
  • Easier compensation handling
  • Simple monitoring
  • Good for complex workflows

Disadvantages

  • Single point of orchestration (must be made highly available)
  • Orchestrator becomes more complex as workflows grow
  • Slightly tighter coupling because the orchestrator knows every service
  • Every new business step requires orchestrator changes

Orchestration vs Choreography

FeatureOrchestrationChoreography
CoordinatorCentral Saga OrchestratorNo coordinator
CommunicationREST / Kafka CommandsKafka Events
WorkflowCentralizedDistributed
DebuggingEasyDifficult
CouplingHigherLower
ScalabilityGoodExcellent
Adding new serviceModify orchestratorSubscribe to an event
Failure handlingOrchestrator invokes compensationServices react to failure events
Best forBusiness workflows with clear controlLarge event-driven architectures

Production Improvements

A real-world orchestrator should also include:

  • Feign Clients or WebClient instead of RestTemplate for inter-service communication.
  • Timeouts and Circuit Breakers (e.g., Resilience4j) to prevent one slow service from blocking the saga.
  • Retry Policies with exponential backoff for transient failures.
  • Persistent Saga State, storing the current step and status in a database so the orchestrator can recover after a crash.
  • Correlation IDs to trace a single saga across all services.
  • Idempotent Compensation APIs, ensuring repeated rollback requests don’t produce inconsistent data.
  • Asynchronous Commands via Kafka if you want centralized orchestration without blocking HTTP calls (hybrid orchestration).

Interview Tip

Many candidates think Orchestration always means REST and Choreography always means Kafka.

That’s not true.

The real difference is who controls the workflow:

  • Orchestration → A central orchestrator decides the next step. It can communicate using REST, gRPC, Kafka commands, or other messaging systems.
  • Choreography → There is no central coordinator. Services react independently to published events, typically through Kafka or another event broker.

So the distinction is about control flow, not the communication protocol.


This version is interview-ready and mirrors the style of your choreography article. It also naturally sets up a follow-up article demonstrating Orchestration Saga with Kafka, where the orchestrator still coordinates the process but sends commands and receives replies asynchronously through Kafka instead of synchronous REST calls—a pattern used in many large-scale production systems.