This project demonstrates a distributed transaction architecture using Reactive Spring and Kafka. The application consists of two services: order-service
and payment-service
, and utilizes Kafka events to ensure consistency between them. The order is confirmed only when the payment is successful. If the user doesn't have sufficient balance, the payment-service denies the payment and stores the transaction in db for future reference.
- Architecture Overview
- Technologies Used
- Setup and Installation
- Internal Flow
- Testing the Application
The system consists of the following components:
- Common Dto: Consists of common components in the applicaiton.
- Order Service: Responsible for managing order creation.
- Payment Service: Manages the payment process for orders.
- Spring Boot for building the services.
- Reactive Spring for non-blocking, reactive programming.
- Apache Kafka for event-driven architecture.
- SQL for storage
- Postman for API testing.
-
Clone the repository:
git clone https://github.com/Ommanimesh2/distributed-transactions-kafka.git cd distributed-transactions-kafka
-
Build the project: Navigate to the root directory and run the following command:
mvn clean install
-
Set up Zookeeper and Kafka: Follow the steps below to install and run Kafka and Zookeeper locally:
- Download and install Apache Kafka from here.
- Start Zookeeper:
bin/zookeeper-server-start.sh config/zookeeper.properties
- Start Kafka broker:
bin/kafka-server-start.sh config/server.properties
-
Run Order Service: Navigate to the
order-service
directory and run:mvn spring-boot:run
-
Database Setup: Make sure your database is set up with the required tables/collections for order service.
-
Run Payment Service: Navigate to the
payment-service
directory and run:mvn spring-boot:run
-
Import Postman Collection: Import the provided Postman collection to test the application APIs. This collection includes test cases for placing orders and handling payments.
-
Order Creation:
- The
Order Service
is responsible for creating orders. When an order is placed, it produces anorder-event
and sends it to Kafka. - Example request:
{ "userId": 2, "productId": 3547, "price": 1200 }
- The
-
Order Event Consumption:
- The
Payment Service
listens for theorder-event
from Kafka. Once it consumes the event, it processes the payment based on the user balance and the order amount.
- The
-
Payment Event:
- Depending on the payment result, the
Payment Service
produces apayment-event
and sends it back to Kafka. This event contains the payment status (SUCCESS
,FAILED
). - Example payment event:
{ "userId": 2, "productId": 3547, "price": 1200, "paymentStatus": "FAILED" }
- Depending on the payment result, the
-
Order Update:
-
The
Order Service
consumes thepayment-event
and updates the order status. If the payment is successful, the order status is marked asCOMPLETED
. Otherwise, the order is marked asCANCELLED
. -
Success Flow:
- Payment is successful →
orderStatus
is updated toCOMPLETED
.
- Payment is successful →
-
Failure Flow:
- Payment fails →
orderStatus
is updated toCANCELLED
.
- Payment fails →
-
-
Place an order using the
Order Service
API:- Endpoint:
POST /orders/create
- Example request body:
{ "userId": 1, "productId": 3923, "price": 3000 }
- Endpoint:
-
Observe the payment processing in
Payment Service
, which consumes the order event and produces a payment event based on user balance. -
Check the order status:
- If the payment is successful, the order status will be
COMPLETED
. - If the payment fails, the order status will be
CANCELLED
.
- If the payment is successful, the order status will be
-
Order with successful payment:
{ "orderId": 3, "userId": 2, "productId": 3923, "price": 3000, "paymentStatus": "SUCCESS", "orderStatus": "COMPLETED" }
-
Order with failed payment:
{ "orderId": 2, "userId": 1, "productId": 3547, "price": 1200, "paymentStatus": "FAILED", "orderStatus": "CANCELLED" }