0% found this document useful (0 votes)
14 views23 pages

Saga Pattern in Spring Boot & RabbitMQ

This tutorial explains the implementation of the Saga pattern in a Spring Boot microservices architecture using RabbitMQ for asynchronous messaging. It details the creation of a money transfer microservice system with debit and credit services, emphasizing event-driven architecture and compensating transactions for error handling. The guide includes step-by-step instructions for setting up the services, configuring RabbitMQ, and managing distributed transactions effectively.

Uploaded by

sushant
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
14 views23 pages

Saga Pattern in Spring Boot & RabbitMQ

This tutorial explains the implementation of the Saga pattern in a Spring Boot microservices architecture using RabbitMQ for asynchronous messaging. It details the creation of a money transfer microservice system with debit and credit services, emphasizing event-driven architecture and compensating transactions for error handling. The guide includes step-by-step instructions for setting up the services, configuring RabbitMQ, and managing distributed transactions effectively.

Uploaded by

sushant
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Saga Pattern with Spring Boot & RabbitMQ Tutorial 29/07/25, 10:41 PM

All Blog Reports


([Link] ([Link] ([Link]
papers)

Return to Microservices list ([Link]

Saga Pattern Microservices Tutorial:


Using the Saga Pattern with Spring
Boot & RabbitMQ
By Onkar Musale In Microservices Posted June 12, 2025

 Search here

Latest Posts Popular Posts

8 Key Benefits of Mobile Devices in Hea


([Link]
devices-in-healthcare)

React Native Maps Tutorial: Master Inte


Distributed transactions across microservices require a different approach than the traditional Google Maps with React Native
([Link]
two phase commit (2PC). In a Spring Boot microservices architecture, where each service
development/react-native-maps-intera
owns its own database and communicates over the network, 2PC becomes complex, slow, and google-maps-tutorial)
error prone due to tight coupling and potential locking across services.
AI Traffic Explodes 357%, Tesla Robots
To address this, the Saga pattern in microservices has become a widely adopted solution. Startup That’s Actually Making Gold
([Link]
Instead of one global transaction, a Saga breaks the workflow into a series of local
in-the-loop-ai-and-tech/ai-traffic-tes
transactions, each managed by an individual service. Once a service completes its part, it
publishes an event (e.g., “DebitCompleted”), which other services consume to trigger their Scaling Mobile Engagement with Flutter

own local operations. Smarter Navigation in Apps


([Link]
development/flutter-deep-linking-guid
This event driven architecture in Spring Boot creates a loosely coupled, scalable system where
each step in the process knows just enough to do its job. If all goes well, the saga flows through AI Heats Up: Nvidia’s China Comeback,
each service to completion. The $1.8 billion Swedish Unicorn
([Link]

But real systems aren’t perfect; failures happen. If any service fails during the process, the in-the-loop-ai-and-tech/ai-heats-up-
agent-swedish-unicorn)
Saga pattern allows you to run compensating transactions, custom logic designed to undo the
effects of previously completed steps. For example, if a credit operation fails, the debit service The Ultimate Guide to Using Chatbots fo
can be asked to roll back the money transfer. Customer Support
([Link]
retail/chatbots-for-ecommerce-suppor
This way, eventual consistency is preserved without distributed locks or tight coordination,
making it ideal for resilient, fault tolerant microservices. This is particularly effective when
paired with robust cloud development services ([Link]

[Link] Page 1 of 23
Saga Pattern with Spring Boot & RabbitMQ Tutorial 29/07/25, 10:41 PM

development?utm_source=blog&utm_medium=internal_link&utm_campaign=saga-pattern-
spring-boot_blog&utm_content=cloud-development) to support scalability and on demand
infrastructure.
TAGS
Follow this Saga pattern microservices tutorial step by step with me, and implement it in your
asynchronous messaging
IDE to fully understand the Saga pattern and how to apply it in your projects. By the end, you’ll ([Link]
be confident in setting up and managing distributed transactions in Spring Boot using the Saga messaging)

pattern.
compensating transactions
In this tutorial, we will build a simple money transfer microservice system consisting of: ([Link]
transactions)
Account-Debit Service (runs on port 8081)

Account-Credit Service (runs on port 8082) distributed systems reliability


([Link]
systems-reliability)
Both services will communicate solely via RabbitMQ microservice communication (using Spring
AMQP), without any REST calls between them. We will use in-memory data and expose REST
endpoints for testing with Postman: distributed transaction spring boot
([Link]
transaction-spring-boot)
Debit Service:

POST /transfer → publishes a TransferRequested event


event driven architecture spring boot
GET /accounts → view in-memory balances ([Link]
driven-architecture-spring-boot)
Credit Service:

GET /accounts → view in-memory balances eventual consistency


([Link]
consistency)

The Saga Workflow:


fault-tolerant microservices
([Link]
Debit Service consumes TransferRequested →
tolerant-microservices)

If there is sufficient balance, debit the “fromAccount”, then publish DebitCompleted;

Otherwise, publish DebitFailed. idempotency in microservices


([Link]
Credit Service consumes DebitCompleted → in-microservices)

If credit logic succeeds, credit the “toAccount”, then publish CreditCompleted;


microservices coordination
Otherwise, publish CreditFailed. ([Link]
coordination)
Debit Service also listens for CreditFailed →

Issue a compensation refund (i.e., add back the amount to “fromAccount”).


rabbitmq microservice communication
([Link]
We’ll implement full AMQP (Advanced Message Queuing Protocol) RabbitMQ saga microservice-communication)
implementation, event DTOs, AccountStore (in memory balances with all methods),
@RabbitListener handlers, and REST controllers. Finally, we’ll run RabbitMQ locally via Docker rabbitmq saga implementation
and test the entire flow with Postman, including a simulated credit failure. This implementation ([Link]
saga-implementation)
can complement more advanced devops services
([Link]
utm_source=blog&utm_medium=internal_link&utm_campaign=saga-pattern-spring- saga pattern example spring boot
([Link]
boot_blog&utm_content=devops) for streamlined automation, testing, and deployment.
pattern-example-spring-boot)

saga pattern microservices


([Link]
pattern-microservices)

service orchestration vs choreography

[Link] Page 2 of 23
Saga Pattern with Spring Boot & RabbitMQ Tutorial 29/07/25, 10:41 PM

([Link]
orchestration-vs-choreography)

spring boot microservices architecture


([Link]
boot-microservices-architecture)

spring boot money transfer microservice


([Link]
boot-money-transfer-microservice)

spring boot saga pattern


([Link]
boot-saga-pattern)
([Link]

utm_source=blog&utm_medium=cta_button_link&utm_campaign=saga-pattern-spring-
spring microservices transaction manag
boot_blog&utm_content=software-development-company ) ([Link]
microservices-transaction-managemen

Technologies
Java 17

Spring Boot 4.0.0

Spring AMQP (spring-boot-starter-amqp)

RabbitMQ (Docker image: rabbitmq:3-management)

Postman (or any REST client)

Project Setup
Open Spring Initializer ([Link] generate two services, Debit Service and
Credit Service, then download the generated ZIP files. Extract and import each service as a
Maven project into your preferred IDE.

Add the following dependencies to your project:

Spring Web – for building RESTful APIs

Spring for RabbitMQ – for asynchronous messaging support using AMQP

Spring Boot DevTools – for automatic restarts and live reload during development

To see how this kind of setup scales and aligns with modern software practices, check out our
in-depth CI/CD with Docker & AWS Blog ([Link]
with-docker-and-aws?utm_source=blog&utm_medium=internal_link&utm_campaign=saga-
pattern-spring-boot_blog&utm_content=ci-cd-with-docker-and-aws) for integrating
continuous deployment in similar microservice architectures.

[Link] Page 3 of 23
Saga Pattern with Spring Boot & RabbitMQ Tutorial 29/07/25, 10:41 PM

1. Running RabbitMQ Locally via Docker

Use Docker to run RabbitMQ:

docker run -d --hostname rabbit --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3-management

AMQP port: 5672

Visit Management UI: [Link] ([Link] (default user/pass:


guest / guest)

Management Home Page:

[Link] Page 4 of 23
Saga Pattern with Spring Boot & RabbitMQ Tutorial 29/07/25, 10:41 PM

2. Common Event DTOs

Each microservice defines its own copy of the following DTO classes. This design supports
microservices coordination and ensures modularity within a distributed system. For each DTO,
ensure that it includes: a constructor with all fields, appropriate getters and setters, and an
overridden toString() method.

Debit Service → [Link]

public class TransferRequested implements Serializable {


private String transferId;
private String fromAccount;
private String toAccount;
private Double amount;
private TransferRequested() {}
}
public class DebitCompleted implements Serializable {
private String transferId;
private String fromAccount;
private String toAccount;
private Double amount;
private DebitCompleted() {}
}
public class DebitFailed implements Serializable {
private String transferId;
private String reason;
private DebitFailed() {}
}
public class CreditFailed implements Serializable {
private String transferId;
private String reason;
private Double refundAmount;
private String refundAccount;
private CreditFailed() {}
}

Credit Service → [Link]

[Link] Page 5 of 23
Saga Pattern with Spring Boot & RabbitMQ Tutorial 29/07/25, 10:41 PM

public class DebitCompleted implements Serializable {


private String transferId;
private String fromAccount;
private String toAccount;
private Double amount;
private DebitCompleted() {}
}
public class CreditCompleted implements Serializable {
private String transferId;
private String toAccount;
private Double amount;
private CreditCompleted() {}
}
public class CreditFailed implements Serializable {
private String transferId;
private String reason;
private Double refundAmount;
private String refundAccount;
private CreditFailed() {}
}

3. AccountStore Component (Both Services)

We simulate accounts in-memory. Place this class in debit service under


[Link]

package [Link];

import [Link];
import [Link];
import [Link];

@Component
public class AccountStore {

private final Map<String, Double> accounts = new ConcurrentHashMap<>([Link]("A", 100.0, "B", 50.0));
public Map<String, Double> getAccounts() {
return accounts;
}
public Double getBalance(String acct) {
return [Link](acct, 0.0);
}
public void updateBalance(String acct, Double newBal) {
[Link](acct, newBal);
}
public boolean debit(String acct, Double amount) {
synchronized (accounts) {
Double balance = getBalance(acct);
if (balance >= amount) {
Double updated = balance - amount;
updateBalance(acct, updated);
return true;
} else {
return false;
}
}
}
public void credit(String acct, Double amount) {
synchronized (accounts) {
Double balance = getBalance(acct);
Double updated = balance + amount;
updateBalance(acct, updated);
}
}
}

Explanation

We use a ConcurrentHashMap to store balances for accounts “A” and “B” by default.

Because we’re not using a real database, this is purely in-memory; all state resets when
the services restart.

Methods:

[Link] Page 6 of 23
Saga Pattern with Spring Boot & RabbitMQ Tutorial 29/07/25, 10:41 PM

getAccounts(): returns the map for GET /accounts endpoint.

getBalance(String): returns current balance or 0.

updateBalance(String, Double): overwrites balance.

debit(String, Double): synchronized check and subtract; logs each step.

credit(String, Double): synchronized add; logs each step.

This idempotency in microservices is crucial to avoid duplicate transactions in event driven


architecture systems.

4. Spring Boot + RabbitMQ Configuration (AMQP)

RabbitMQ is a message broker that uses the AMQP protocol (Advanced Message Queuing
Protocol) to send and receive messages between different systems in a reliable and
asynchronous manner.

Spring Boot makes it easy to integrate RabbitMQ using the Spring AMQP module. It abstracts
the low-level AMQP details, enabling seamless RabbitMQ microservice communication with
simple annotations and configurations.

You use @RabbitListener to receive messages from a queue.

You use [Link]() to send messages to an exchange with a


routing key.

Spring handles message serialization, deserialization, connection management, retries,


and error handling under the hood.

Together, Spring Boot and RabbitMQ provide a clean and efficient way to enable event-driven
communication between microservices or components in a distributed system.

This idempotency in microservices is crucial to avoid duplicate transactions in event-driven


architecture systems. For additional reading on building resilient systems with messaging
queues and distributed services, refer to our guide on Spring Boot with Apache Kafka
([Link]
utm_source=blog&utm_medium=internal_link&utm_campaign=saga-pattern-spring-
boot_blog&utm_content=spring-boot-apache-kafka-guide).

Exchange, Routing Keys and Queues Configurations:

We configure a single Direct Exchange named [Link], plus five queues:

[Link]

[Link]

[Link]

[Link]

[Link]

Bindings route messages by routing key, e.g. “[Link]” →


[Link], “[Link]” → [Link], etc.

[Link] Page 7 of 23
Saga Pattern with Spring Boot & RabbitMQ Tutorial 29/07/25, 10:41 PM

5. Debit Service Implementation (Port 8081)

Debit-service package structure

5.1 [Link] (Debit Service)

[Link]=debit-service
[Link]=8081
[Link]=localhost
[Link]=5672
[Link]=guest
[Link]=guest

5.2 [Link]

[Link] Page 8 of 23
Saga Pattern with Spring Boot & RabbitMQ Tutorial 29/07/25, 10:41 PM

package [Link];

import [Link];
import [Link];

@SpringBootApplication
public class DebitServiceApplication {
public static void main(String[] args) {
[Link]([Link], args);
}
}

5.3 [Link]

Add the AccountStore class from the above given example for debit service.

5.4 [Link]

package [Link];

import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link].Jackson2JsonMessageConverter;
import [Link];
import [Link];
import [Link];

@Configuration
public class RabbitMQConfig {

public static final String EXCHANGE = "[Link]";

public static final String QUEUE_TRANSFER_REQUESTED = "[Link]";


public static final String QUEUE_DEBIT_COMPLETED = "[Link]";
public static final String QUEUE_DEBIT_FAILED = "[Link]";
public static final String QUEUE_CREDIT_COMPLETED = "[Link]";
public static final String QUEUE_CREDIT_FAILED = "[Link]";

public static final String RK_TRANSFER_REQUESTED = "[Link]";


public static final String RK_DEBIT_COMPLETED = "[Link]";
public static final String RK_DEBIT_FAILED = "[Link]";
public static final String RK_CREDIT_COMPLETED = "[Link]";
public static final String RK_CREDIT_FAILED = "[Link]";

@Bean
DirectExchange sagaExchange() {
return new DirectExchange(EXCHANGE);
}

@Bean
Queue transferRequestedQueue() {
return [Link](QUEUE_TRANSFER_REQUESTED).build();
}

@Bean
Queue debitCompletedQueue() {
return [Link](QUEUE_DEBIT_COMPLETED).build();
}

@Bean
Queue debitFailedQueue() {
return [Link](QUEUE_DEBIT_FAILED).build();
}

@Bean
Queue creditCompletedQueue() {
return [Link](QUEUE_CREDIT_COMPLETED).build();
}

@Bean
Queue creditFailedQueue() {

[Link] Page 9 of 23
Saga Pattern with Spring Boot & RabbitMQ Tutorial 29/07/25, 10:41 PM

return [Link](QUEUE_CREDIT_FAILED).build();
}

@Bean
Binding bindTransferRequested(Queue transferRequestedQueue, DirectExchange exchange) {
return [Link](transferRequestedQueue).to(exchange).with(RK_TRANSFER_REQUESTED);
}

@Bean
Binding bindDebitCompleted(Queue debitCompletedQueue, DirectExchange exchange) {
return [Link](debitCompletedQueue).to(exchange).with(RK_DEBIT_COMPLETED);
}

@Bean
Binding bindDebitFailed(Queue debitFailedQueue, DirectExchange exchange) {
return [Link](debitFailedQueue).to(exchange).with(RK_DEBIT_FAILED);
}

@Bean
Binding bindCreditCompleted(Queue creditCompletedQueue, DirectExchange exchange) {
return [Link](creditCompletedQueue).to(exchange).with(RK_CREDIT_COMPLETED);
}

@Bean
Binding bindCreditFailed(Queue creditFailedQueue, DirectExchange exchange) {
return [Link](creditFailedQueue).to(exchange).with(RK_CREDIT_FAILED);
}

@Bean
MessageConverter converter() {
return new Jackson2JsonMessageConverter();
}

@Bean
AmqpTemplate amqpTemplate(ConnectionFactory connectionFactory) {
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
[Link](converter());
return rabbitTemplate;
}
}

5.5 [Link]

[Link] Page 10 of 23
Saga Pattern with Spring Boot & RabbitMQ Tutorial 29/07/25, 10:41 PM

package [Link];

import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];

@Component
public class DebitEventHandler {

private final RabbitTemplate rabbitTemplate;


private final AccountStore accountStore;

public DebitEventHandler(RabbitTemplate rabbitTemplate, AccountStore accountStore) {


[Link] = rabbitTemplate;
[Link] = accountStore;
}

@RabbitListener(queues = RabbitMQConfig.QUEUE_TRANSFER_REQUESTED)
public void handleTransferRequest(TransferRequested request) {
boolean success = [Link]([Link](), [Link]());
if (success) {
DebitCompleted event = new DebitCompleted([Link](), [Link](),
[Link](), [Link]());
[Link]([Link], RabbitMQConfig.RK_DEBIT_COMPLETED, event);
} else {
DebitFailed event = new DebitFailed([Link](),
"Insufficient balance in account: " + [Link]());
[Link]([Link], RabbitMQConfig.RK_DEBIT_FAILED, event);
}
}

@RabbitListener(queues = RabbitMQConfig.QUEUE_CREDIT_FAILED)
public void handleCreditFailed(CreditFailed event) {
[Link]([Link](), [Link]());
}
}

5.6 [Link]

package [Link];

import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];

@RestController
@RequestMapping("/transfer")
public class TransferController {

private final RabbitTemplate rabbitTemplate;

public TransferController(RabbitTemplate rabbitTemplate) {


[Link] = rabbitTemplate;
}

@PostMapping
public String requestTransfer(@RequestBody TransferRequested request) {
[Link]([Link], RabbitMQConfig.RK_TRANSFER_REQUESTED, request);
return "Transfer requested: " + [Link]();
}
}

5.7 [Link]

[Link] Page 11 of 23
Saga Pattern with Spring Boot & RabbitMQ Tutorial 29/07/25, 10:41 PM

package [Link];

import [Link];

import [Link];
import [Link];
import [Link];

import [Link];

@RestController
@RequestMapping("/accounts")
public class BalanceController {
private final AccountStore accountStore;

public BalanceController(AccountStore accountStore) {


[Link] = accountStore;
}

@GetMapping
public Map<String, Double> getAccounts() {
return [Link]();
}
}

6. Credit Service Implementation (Port 8082)

Credit-service package structure

*PackageExplorerX ⽇g9
vcredit-service[boot][devtools]
vsrc/main/java
v#[Link]
>[Link]
v##[Link]
>[Link]
v#[Link]
>[Link]
[Link]
>[Link]
>[Link]
>[Link]
v@[Link]
>[Link]
v#[Link]
>[Link]
v#sic/main/resources
&static
Btemplates
[Link]
>Esic/test/java
>BAJRESystemLibrary[JavaSE-17]|
>alMavenDependencies
>asrc
atarget
[Link]
mvnw

[Link]
м[Link] MOBISOFT
›•debit-service[boot][devtools]

6.1 [Link] (Credit Service)

[Link]=credit-service
[Link]=8082
[Link]=localhost
[Link]=5672
[Link]=guest
[Link]=guest

6.2 [Link]

[Link] Page 12 of 23
Saga Pattern with Spring Boot & RabbitMQ Tutorial 29/07/25, 10:41 PM

package [Link];

import [Link];
import [Link];

@SpringBootApplication
public class CreditServiceApplication {
public static void main(String[] args) {
[Link]([Link], args);
}
}

6.3 [Link] (Credit Service)

package [Link];

import [Link];
import [Link];
import [Link];

@Component
public class AccountStore {
private final Map<String, Double> accounts = new ConcurrentHashMap<>([Link]("C", 20.0, "D", 80.0));

public Map<String, Double> getAccounts() {


return accounts;
}

public Double getBalance(String acct) {


return [Link](acct, 0.0);
}

public void updateBalance(String acct, Double newBal) {


[Link](acct, newBal);
}

public boolean debit(String acct, Double amount) {


synchronized (accounts) {
Double balance = getBalance(acct);
if (balance >= amount) {
Double updated = balance - amount;
updateBalance(acct, updated);
return true;
} else {
return false;
}
}
}

public void credit(String acct, Double amount) {


synchronized (accounts) {
Double balance = getBalance(acct);
Double updated = balance + amount;
updateBalance(acct, updated);
}
}
}

6.4 [Link] (Credit Service)

Use the same exchange and queue names as the Debit Service, so that they share the same
RabbitMQ infrastructure.

6.5 [Link]

[Link] Page 13 of 23
Saga Pattern with Spring Boot & RabbitMQ Tutorial 29/07/25, 10:41 PM

package [Link];

import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];

@Component
public class CreditEventHandler {

private final RabbitTemplate rabbitTemplate;


private final AccountStore accountStore;

public CreditEventHandler(RabbitTemplate rabbitTemplate, AccountStore accountStore){


[Link] = rabbitTemplate;
[Link] = accountStore;
}

@RabbitListener(queues = RabbitMQConfig.QUEUE_DEBIT_COMPLETED)
public void handleDebitCompleted(DebitCompleted event) {
// Simulate a failure for a specific transferId "FAIL-CREDIT"
if ("FAIL-CREDIT".equals([Link]())) {
CreditFailed cf = new CreditFailed([Link](), "Simulated credit failure", [Link](),
[Link]());
[Link]([Link], RabbitMQConfig.RK_CREDIT_FAILED, cf);
return;
}
[Link]([Link](), [Link]());

CreditCompleted cc = new CreditCompleted([Link](), [Link](), [Link]());


[Link]([Link], RabbitMQConfig.RK_CREDIT_COMPLETED, cc);
}
}

6.6 [Link]

package [Link];

import [Link];
import [Link];
import [Link];

import [Link];

@RestController
@RequestMapping("/accounts")
public class BalanceController {
private final AccountStore accountStore;

public BalanceController(AccountStore accountStore) {


[Link] = accountStore;
}

@GetMapping
public Map<String, Double> getAccounts() {
return [Link]();
}
}

7. Testing the Saga Flow via Postman

To validate the spring boot money transfer microservice, start both the Debit and Credit
services. Ensure each service runs on its assigned port and is connected to the RabbitMQ
server (typically on port 5672)..

7.1 Debit Service Accounts:

[Link] Page 14 of 23
Saga Pattern with Spring Boot & RabbitMQ Tutorial 29/07/25, 10:41 PM

Check the /accounts endpoints of each service to view the current account balances. The Debit
Service contains two accounts, A and B with balances { “A”: 100.0, “B”: 50.0 }, while the
Credit Service includes accounts C and D with balances { “C”: 20.0, “D”: 80.0 }.

GET [Link]

7.2 Credit Service Accounts:

GET [Link]

7.3 Perform Successful Transfer

To simulate a successful money transfer, initiate:

POST [Link]

[Link] Page 15 of 23
Saga Pattern with Spring Boot & RabbitMQ Tutorial 29/07/25, 10:41 PM

Working:

Debit Service receives a TransferRequested with transferId=TXN1001.

[Link](“A”, 30.0) → succeeds (100.0 ≥ 30.0). A’s new balance = 70.0.

Publishes DebitCompleted(“TXN1001″,”A”,”C”,30.0).

Verify Debit Service Account Balances:

GET [Link] → {“A”:70.0,”B”:50.0}

Credit Service consumes DebitCompleted:

Does not match “FAIL-CREDIT”, so [Link](“C”, 30.0) → C’s new


balance = 50.0.

Publishes CreditCompleted(“TXN1001″,”A”,30.0).

Verify Credit Service Account Balances:

GET [Link] → {“C”:50.0,”D”:80.0}

[Link] Page 16 of 23
Saga Pattern with Spring Boot & RabbitMQ Tutorial 29/07/25, 10:41 PM

7.4 Insufficient Funds (Debit Failure)

To simulate failure in debit:

POST [Link]

Reach Out To
Us
What Happens:
Your full name*
Debit Service tries [Link](“A”,1000.0) → fails (70.0 < 1000.0).

Publishes DebitFailed(“TXN1002″,”Insufficient balance…”). Your email address*

Credit Service does not react to DebitFailed (no listener).


Phone number
Balances remain unchanged. (optional)

India
Verify:
How can we help you?
Debit Service:

GET [Link] → {“A”:70.0,”B”:50.0} By submitting this form,


you explicitly agree to
Mobisoft Infotech Privacy
Credit Service remains the same.
Policy
([Link]
7.5 Simulated Credit Failure (Compensation) policy) and Terms of
Service

[Link] Page 17 of 23
Saga Pattern with Spring Boot & RabbitMQ Tutorial 29/07/25, 10:41 PM

To simulate a credit failure and trigger the saga pattern compensation: ([Link]
of-services).

POST [Link]
REACH OUT
TO US

Working:

Debit Service:

[Link](“A”,20.0) → succeeds (A’s balance = 50.0).

Publishes DebitCompleted(“FAIL-CREDIT”,”A”,20.0).

Credit Service receives DebitCompleted(“FAIL-CREDIT”,…):

Matches “FAIL-CREDIT” → publishes CreditFailed(“FAIL-CREDIT”, “Simulated


credit failure”).

Debit Service listens for CreditFailed:

[Link](“A”,50.0) (compensation refund). A’s balance goes back to


100.0 (50.0 + 50.0).

Verify:

Debit Service:

GET [Link] → {“A”:100.0,”B”:50.0}

[Link] Page 18 of 23
Saga Pattern with Spring Boot & RabbitMQ Tutorial 29/07/25, 10:41 PM

Credit Service remains unchanged.

State of RabbitMQ Exchanges and Queues on Management Portal

8. Conclusion & Next Steps

We’ve successfully built a Spring Boot money transfer microservice using the Saga pattern that
demonstrates:

RabbitMQ (AMQP) for asynchronous messaging

@RabbitListener for consuming events

AccountStore for in memory balances

REST APIs for testing with Postman:

POST /transfer (Debit Service)

GET /accounts (both services)

Next Steps:

Use a database: Persist accounts and saga state for production.

Docker Compose: Combine both services and RabbitMQ into one [Link].

Unit tests: Write tests for each handler using @SpringBootTest and mocks.

Security: Add authentication/authorization to REST endpoints.

[Link] Page 19 of 23
Saga Pattern with Spring Boot & RabbitMQ Tutorial 29/07/25, 10:41 PM

Wrapping Up:
We’ve successfully implemented a distributed transaction system using the Saga pattern. Now
you can extend this pattern for more complex workflows and scale it for production. Keep
experimenting with advanced features like fault tolerance and resilience, and don’t forget to
secure your services for a complete, production ready solution.

If you’re looking to build scalable microservices or distributed systems, explore our end-to-
end software development services ([Link]
development-company?utm_source=blog&utm_medium=internal_link&utm_campaign=saga-
pattern-spring-boot_blog&utm_content=software-development-company) tailored for
modern enterprise needs. You can explore the complete source code on our GitHub
([Link] repository.

([Link]

utm_source=blog&utm_medium=cta_button_link&utm_campaign=saga-pattern-spring-

boot_blog&utm_content=contact-us )

Author's Bio

Onkar Musale is a Senior Software Engineer at Mobisoft Infotech


([Link]
utm_source=blog&utm_medium=internal_link&utm_campaign=saga-
pattern-spring-boot_blog&utm_content=home-page) with over 6.5
years of experience in Java backend development and cloud
Onkar Musale technologies, I specialize in designing scalable microservices and robust
RESTful APIs using Java Spring Boot and Golang. I’m passionate about
leveraging AWS, Docker, and Kubernetes to build high-performance,
cost-efficient solutions. My expertise spans database management
(MySQL, PostgreSQL, MongoDB), API documentation, payment gateway
integrations, and advanced cloud configurations. I’m a quick learner,
resilient, and always eager to adapt to new technologies, dedicated to
delivering quality solutions that drive business success.

([Link]

[Link] Page 20 of 23
Saga Pattern with Spring Boot & RabbitMQ Tutorial 29/07/25, 10:41 PM

Name

Let's Stay Business Email

Connected By submitting this form, you explicitly agree to Mobisoft Infotech


Privacy Policy ([Link] and
Get our latest posts delivered right to your inbox. Terms of Service ([Link]

SUBSCRIBE

Insights
Have a glimpse of our insightful blogs on exciting topics.

Resilience4j Circuit Breaker Tutorial Saga Pattern Microservices Tutorial:


along with Retry & Bulkhead patterns Using the Saga Pattern with Spring
for Spring Boot Microservices Boot & RabbitMQ
([Link]
([Link]
circuit-breaker-retry-bulkhead-spring-boot) pattern-spring-boot-rabbitmq-tutorial)

View All Posts  (/resources/blog)

Contact us
Submit the form to schedule a meeting and discover how we can assist you

[Link] Page 21 of 23
Saga Pattern with Spring Boot & RabbitMQ Tutorial 29/07/25, 10:41 PM

Call us
Your full name*
USA +1-855-572-2777([Link]

IND +91-858-600-8627([Link]
Your email address*
Book a ([Link]
meeting us)
India
Business inquiry
business@[Link]
Phone number (optional) ([Link]

General information
info@[Link]
How can we help you? ([Link]

Career with us
jobs@[Link]
([Link]

Locations
By submitting this form, you explicitly agree to
USA
Mobisoft Infotech
Privacy ([Link] 5718, Westheimer Rd Suite
Policy policy) 1000 Houston, TX 77057
and
Terms of ([Link] INDIA
Service of-services) Level 2, Trident Business Center,
. Opposite Audi Showroom, Baner, Pune -
411045

Submit

Services Solutions Industries Business Inquiry

AI Enablement & Consulting Data Engineering Retail & E-commerce +1-855-572-2777 (USA)
Transportation &
([Link]
([Link]
Logistics (/industry/retail- ([Link]
intelligence) engineering-services) ecommerce-solutions)
Retail & E-Commerce +91-858-600-8627
Digital Product Engineering UX/UI Design Logistics & Transportation
(India)
([Link]
([Link] (/industry/transportation-
product-engineering-services)ux-design) logistics) ([Link]
Healthcare
Product Discovery Test Automation Sports & Entertainment business@[Link]
([Link]
([Link] (/industry/digital- ([Link]
discovery-software-solutions) automation) Others transformation-sports-
entertainment)
Custom Software Development RPA
([Link]
([Link] Healthcare
development-company) process-automation-services) (/industry/healthcare- Mobisoft Infotech
digital-transformation) About (/about-us)
Digital Transformation Digital Commerce
([Link]
([Link] High Tech & Startups Our Approach (/our-
transformation-services) commerce) (/startup-it-solutions- approach)
services)
Software Sustenance Team Augmentation Partners (/software-
([Link]
([Link] development-partners)
maintenance-and-support) augmentation)
Tech Stack (/technology-
Mobile App Development Cybersecurity Consulting ([Link] stack)
([Link]
app-development-company) Careers (/jobs-at-
mobisoft)

[Link] Page 22 of 23
Saga Pattern with Spring Boot & RabbitMQ Tutorial 29/07/25, 10:41 PM

Cloud Services HIPAA Consulting Blog (/resources/blog)


([Link]
([Link]
development) consulting-services) Engagement Models
(/engagement-models)
Web Development Salesforce Consulting
([Link]
([Link] Contact (/contact-us)
web-development-company) consulting)
Cyber Fraud & Scam Alert
DevOps Services Startup Consulting (/cyber-scams-misusing-
([Link]
([Link] mobisoft-infotech-name)
it-solutions-services)
IoT Services
([Link]
Shopify Consulting
development-services) ([Link]

IT Consulting
([Link]
consulting-company)

USA (Houston, Texas) ([Link]


([Link]
([Link]
([Link]
([Link]
([Link]
([Link]
([Link]
([Link]
INDIA (Pune, Maharashtra) ([Link] Infotech/131035500270720)
infotech)

Privacy Policy (/privacy-policy)

([Link]
Terms of Services (/terms-of-services)

Sitemap (/sitemap-mi)

TOP
MOBILE APP
DEVELOPERS
SelectedFirms

© 2025 Mobisoft Infotech


R
TOP IT
SERVICE COMPANY
INDIA
[Link]

Certified Member 2021

[Link] Page 23 of 23

Common questions

Powered by AI

RabbitMQ is configured to use a single Direct Exchange named money.transfer.exchange, along with five queues for different transaction states: transfer.requested.queue, debit.completed.queue, debit.failed.queue, credit.completed.queue, and credit.failed.queue. These queues are bound to the exchange with specific routing keys such as transfer.requested and debit.completed. The Debit and Credit services utilize similar RabbitMQ infrastructure configurations to send and receive messages, using RabbitTemplate for sending and @RabbitListener for consuming messages from these queues .

RabbitMQ ensures message delivery reliability through mechanisms like acknowledgement of messages, persistent queues, and retries. Messages sent to queues are acknowledged by consumers, confirming successful processing, reducing the risk of message loss. In case of network failures or service downtime, RabbitMQ can re-deliver the messages due to its message persistence feature, ensuring that messages are not lost in transit and eventually reach their intended destination .

The Saga pattern manages distributed transactions by breaking them down into a series of local transactions. In this spring boot microservice architecture, the Saga pattern ensures consistency across the Debit and Credit services by coherently handling each service's operations and compensations when a failure occurs. It does this asynchronously, using RabbitMQ to enable communication and transaction status tracking between services, allowing for eventual consistency and resilience .

Using Docker to run RabbitMQ simplifies deployment and ensures consistent environments for the RabbitMQ message broker across different development and test setups. The implementation involves running a RabbitMQ Docker image using the command `docker run -d --hostname rabbit --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3-management`, setting up ports for AMQP protocol communications and management UI. This approach enhances flexibility, scalability, and ensures isolation, facilitating easier management and monitoring by using the RabbitMQ Management UI .

The Saga pattern offers significant advantages over traditional distributed transactions by providing greater scalability, fault tolerance, and eventual consistency without requiring a centralized coordination process that could become a single point of failure. It decomposes a distributed transaction into a series of local transactions coordinated through events (via RabbitMQ), which allows each service to independently manage its state changes and failures. This approach reduces the complexity of rollback mechanisms needed in traditional models and enhances system resilience to component failures .

The transfer microservice system uses RabbitMQ for asynchronous messaging between the Debit and Credit services instead of REST calls. This approach employs the AMQP protocol for reliable communication. The Debit service publishes events like TransferRequested to a queue when it receives a transaction request. If successful, it publishes a DebitCompleted event. Alternatively, if a debit fails due to insufficient funds, it publishes a DebitFailed event. The Credit service listens to these events and accordingly updates the account balances by publishing a CreditCompleted or CreditFailed event, and the Debit service can issue compensation refunds based on the CreditFailed event .

The AccountStore component maintains in-memory balances and provides methods for debit and credit operations ensuring thread safety through synchronization. It handles the retrieval and updating of account balances used in transaction processing. Both the Debit and Credit services implement an AccountStore with similar logic to update or validate account balances during transactions. Synchronization ensures consistency in concurrent operations across services .

Idempotency is achieved through synchronized checks in account operations, ensuring that repeated processing of the same transaction does not result in unintended changes. This is crucial in the system's event-driven architecture as it prevents duplicate transactions that could arise from message re-delivery or retries inherent in asynchronous communication. Guarantees of idempotency are essential for maintaining data consistency and reliability in distributed systems like this .

The system simulates a credit failure using a specified transferId 'FAIL-CREDIT'. When the Credit Service receives a DebitCompleted event with this ID, it deliberately doesn't apply the credit and instead publishes a CreditFailed event. The Debit Service, upon receiving this event, performs a compensation action by crediting back the deducted amount to the original account. This simulation tests the robustness of the Saga pattern, ensuring compensating transactions are executed correctly in failure scenarios .

Spring Boot facilitates integration with RabbitMQ through the Spring AMQP module, which abstracts low-level AMQP details, providing annotations and configuration support. This allows seamless RabbitMQ microservice communication by simplifying message serialization, deserialization, connection management, and error handling. The benefits include reduced complexity in managing message queuing and improved developer productivity as Spring Boot's abstraction allows focusing on business logic rather than message protocol intricacies .

You might also like