Spring Boot Microservices Choreography Example
Introduction
This project demonstrates the choreography saga pattern in Spring Boot microservices architecture using Apache Kafka,
Spring Cloud Eureka, and Spring Cloud API Gateway.In modern microservices architectures, handling distributed transactions across multiple services is a complex problem. Traditional ACID transactions do not scale well across service boundaries, especially in cloud‑native and event‑driven systems.
The goal is to build a loosely coupled, event‑driven, and highly scalable system where services coordinate business transactions using Kafka events and asynchronous calls. So, each service consumes events to trigger local transactions and publishes new events to trigger subsequent steps, enhancing loose coupling, scalability, and resilience.
Saga Choreography
A Saga is a sequence of local transactions where each step publishes an event that triggers the next step.
There are two main saga styles:
Orchestration
- A central controller manages the workflow.
- Simpler flow visibility, but higher coupling.
An example on orchestration can be found Spring Boot Microservices Orchestration Example.
Choreography
- No central coordinator.
- Each service reacts to events and publishes new ones.
- More scalable and resilient.
- Better fits event‑driven architectures.
In this Saga Choreography example, Kafka becomes the backbone of the transaction flow.
Tech Stack
- Spring Boot for all services
- Spring REST APIs
- Spring Cloud Eureka Server for service discovery
- Spring Cloud API Gateway for routing requests to services
- MySQL
- Kafka
- Maven
High‑Level Architecture
Systems involved – we will build seven Spring Boot applications:
- discovery-service (Eureka Server) – 8761
- api-gateway (Spring Cloud Gateway) – 8080
- order-service (Saga initiator) – 8081
- payment-service (Processes payments) – 8082
- inventory-service (Checks & reserves stock) – 8083
- notification-service (Sends SMS/Email-style notifications) – 8084
- common-dto (Shared DTO Module)
- discover-service is used for service registration
- api-gateway is single entry point
- order-service is saga initiator
- payment-service is used for processing payment
- inventory-service is used for stock validation
- notification-service is used for event notifications
- common-dto is shared event models
Each of the above services:
- Has its own database
- Is independently deployable
- Communicates only via Kafka events
- No service calls another service directly
Business Flow:
Client → API Gateway → Order Service → Kafka
→ Payment Service → Kafka
→ Inventory Service → Kafka
→ Notification Service → Kafka
→ Order Service (final status update)
Event‑Driven Workflow
Apache Kafka is used for event driven flow. Kafka uses the following topics:
- order-created
- payment-completed
- payment-failed
- inventory-reserved
- inventory-failed
- notification-send
- order-status-updated
Kafka guarantees:
- Asynchronous communication
- Loose coupling
- Fault tolerance (events survive service restarts)
Startup Kafka
Open Command Prompt and run:
Start Zookeeper
bin\windows\zookeeper-server-start.bat config\zookeeper.properties Start Kafka
bin\windows\kafka-server-start.bat config\server.properties If you have enabled auto.create.topics.enable=true in server.properties then you don’t need to create kafka topics manually, otherwise you can create them manually using the following commands:
bin\windows\kafka-topics.bat --create --topic order-created --bootstrap-server localhost:9092
bin\windows\kafka-topics.bat --create --topic payment-completed --bootstrap-server localhost:9092
bin\windows\kafka-topics.bat --create --topic payment-failed --bootstrap-server localhost:9092
bin\windows\kafka-topics.bat --create --topic inventory-reserved --bootstrap-server localhost:9092
bin\windows\kafka-topics.bat --create --topic inventory-failed --bootstrap-server localhost:9092
bin\windows\kafka-topics.bat --create --topic notification-send --bootstrap-server localhost:9092 MySQL Server Startup
Make sure MySQL server is running. The databases are created automatically due to ?createDatabaseIfNotExist=true
You will see the following databases corresponding your services:
- order-service: orderdb
- payment-service: paymentdb
- inventory-service: inventorydb
- notification-service: notificationdb
You can insert one product in the inventory to test the flow when you startup the services:
INSERT INTO inventory (product_id, quantity)
VALUES ('P1001', 10); Microservices Startup
Start the services in the following order:
- Discovery Service (Port 8761)
- Order Service (8081)
- Payment Service (8082)
- Inventory Service (8083)
- Notification Service (8084)
- API Gateway (8080)
API Gateway Test URLs
When microservices run, you can test endpoints like:
POST http://localhost:8080/orders/create
POST http://localhost:8080/orders
GET http://localhost:8080/payments/status/123
GET http://localhost:8080/inventory/check/abc
End‑to‑End Saga Flow
- All services register to Eureka
- All HTTP requests route through Gateway
- Kafka event flow implements Saga Choreography
Test Flow
Client sends request
POST /orders (via API Gateway)
Order Service
- Saves order with status ORDER_CREATED
- Publishes order-created
Payment Service
- Consumes order-created
- If amount ≤ 5000 → payment succeeds
- Publishes payment-completed
Inventory Service
- Consumes payment-completed
- Checks stock
- Publishes inventory-reserved
Order Service
Final status updated to ORDER_COMPLETED
Notification Service
Saves notification logs
Summary
- Saga completes
- No distributed locks
- No blocking calls
Test Examples
Successful Test
Request:
POST http://localhost:8080/orders
Content-Type: application/json
Body:
{
"userId": "user100",
"amount": 1200.50
} Expected Flow (Logs):
order-service – Order Created Event Sent
payment-service – Payment Completed Event Sent
inventory-service – Inventory Reserved Event Sent
notification-service – Notification saved (Inventory Reserved)
order-service – Order Completed
Expected DB Output:
orders.order_status = ORDER_COMPLETED
Failure Test
Request
POST http://localhost:8080/orders
Content-Type: application/json
Body:
{
"userId": "user200",
"amount": 6500
} Expected Flow (logs):
order-service – Order Created
payment-service – Payment Failed
notification-service – notification: Payment failed
order-service – Order Cancelled
Verify Notification Storage
You can verify the notification by the following request.
Request:
GET http://localhost:8080/notifications
Expected sample result:
[
{
"id": 1,
"orderId": "123e-uuid",
"message": "Payment successful for Order: 123e-uuid",
"email": "customer@example.com"
}
] Verify Payment and Inventory Records
Payment:
http://localhost:8080/payments/{orderId}
Inventory:
http://localhost:8080/inventory/{orderId}
Full Saga Flow Summary
Client → POST /orders
↓
Order Service → publish order-created
↓
Payment Service → payment-completed / payment-failed
↓
Inventory Service → inventory-reserved / inventory-failed
↓
Order Service → updates order state
↓
Notification Service → sends notification email
Conclusion
This project demonstrates a real‑world, end‑to‑end Saga Choreography implementation using Spring Boot microservices and Kafka, without shortcuts or hidden orchestration logic.
No comments
Leave a comment