Skip to content

Andrij72/order-service

Repository files navigation


🧾 Order Service (Saga Version)

Order Service manages the lifecycle of orders within the MicroServiceGrid system-DDD and is a microservice responsible for managing orders in an e-commerce system.
This is the updated Saga version, replacing the legacy CRUD approach.
You can find the legacy CRUD version here: Legacy CRUD Version

The service supports pagination, sorting, and filtering by status or user email. It is part of MicroserviceGrid project and communicates with other services and infrastructure as follows:

📌 Features

  • Order management: create, update, cancel, and fetch orders.
  • Saga orchestration using Kafka for reliable business processes:
    • Inventory confirmation
    • Payment processing
  • Outbox pattern for reliable Kafka event publishing.
  • Validation via @Valid annotations.
  • Custom exceptions and global handling (OrderNotFoundException, ProductOutOfStockException, etc.).

⚙️ Technology Stack

  • Java 21
  • Spring Boot 3
  • Spring Data JPA
  • Kafka (Spring Kafka)
  • MySQL (Flyway migrations)
  • Lombok
  • Avro for event serialization

📡 Kafka Integration

The service listens to the following topics:

Topic Description Listener Method
inventory-confirmed Inventory confirmed handleInventoryConfirmed(InventoryEvent)
inventory-rejected Inventory rejected handleInventoryRejected(InventoryEvent)
payment-completed Payment completed handlePaymentCompleted(String orderNumber)
payment-failed Payment failed handlePaymentFailed(String orderNumber)

Events are published using Outbox, processed by a Kafka Worker.


📄 REST API

Base URL: /api/v1/orders

Create Order

POST /api/v1/orders
Content-Type: application/json

{
"userDetails": {
  "email": "[email protected]",
  "name": "Andrii"
},
"items": [
  { "productId": "123", "quantity": 2 }
]
}

Response: 201 Created

Get Order

GET /api/v1/orders/{orderNumber}

Response: 200 OK

Get All Orders (pagination + filters)

GET /api/v1/orders?page=0&size=10&sort=createdAt,desc&status=CREATED&[email protected]

Update Full Order

PUT /api/v1/orders/{orderNumber}
Content-Type: application/json

Cancel Order

PATCH /api/v1/orders/{orderNumber}/cancel

🗂 Project Structure

  src/main/java/com/akul/microservices/order
  ├─ controller   # REST endpoints
  ├─ application  # DTOs and services
  ├─ domain       # Models, OrderStatus, Exceptions
  ├─ event        # Events (PaymentRequestedEvent)
  ├─ infrastructure
  │   ├─ messaging/kafka  # Kafka Listeners & Topic Resolver
  │   ├─ outbox           # Outbox pattern
  │   ├─ persistence      # JPA repositories
  │   └─ worker           # Outbox Publisher
  └─ resources
  ├─ db/migration     # Flyway SQL migrations
  └─ application*.properties

🔄 ## 🔹 Saga Flow (Order Perspective)

     User
      │
      ▼
     Order Service
      │
      ├── validate order
      ├── persist order in DB
      ├── save ORDER_CREATED event to Outbox
      │
      ▼
     Outbox Worker → Kafka
      │
      ▼
     Inventory Service
      ├── check stock
      ├── reserve inventory (per SKU)
      ├── create reservation (TTL)
      ├── save INVENTORY_CONFIRMED / INVENTORY_REJECTED / INVENTORY_EXPIRED to Outbox
      │
      ▼
     Outbox Worker → Kafka
      │
      ▼
     Order Service reacts
      ├── CONFIRMED → publish PAYMENT_REQUESTED
      └── REJECTED / EXPIRED → mark order as FAILED
      │
      ▼
     Payment Service
      ├── process payment
      ├── save PAYMENT_COMPLETED / PAYMENT_FAILED to Outbox
      │
      ▼
     Outbox Worker → Kafka
      │
      ▼
     Order Service updates order status
      ├── PAYMENT_COMPLETED → COMPLETED
      └── PAYMENT_FAILED → FAILED + INVENTORY_CANCELLED

⏳ TTL Expiration Flow

Scheduler
│
├── find expired reservations
├── mark EXPIRED
├── release inventory
├── save INVENTORY_EXPIRED to Outbox
▼
Kafka → Order Service
│
└── update order as FAILED

🧠 Key Design Principles

  • Outbox pattern ensures reliable event delivery
  • Idempotent operations via (order_id, sku_code) uniqueness
  • TTL reservations prevent stock locking
  • No distributed transactions — each service updates its state based on events
  • Multi-SKU orders processed independently

📦 Order States

PENDING
├─> INVENTORY_RESERVED
│    ├─> PAYMENT_PROCESSING
│    │    ├─> PAID
│    │    └─> FAILED
├─> FAILED
└─> CANCELLED

🔑 Key Features

  • Create orders via REST API
  • Confirm or reject orders through Saga
  • Automatic status updates
  • Outbox + Kafka for guaranteed event delivery
  • Idempotent handling to avoid duplication

🔗 Public API (OrderController)

Method Endpoint Description
POST /api/v1/orders Create an order
PATCH /api/v1/orders/{orderNumber}/cancel Cancel an order
GET /api/v1/orders/{orderNumber} Get order status

Example:

POST /api/v1/orders
Content-Type: application/json

  {
  "items": [
  { "sku": "iPhone-15", "productName": "iPhone 15", "price": 1500.0, "quantity": 1 }
  ],
  "userDetails": {
  "email": "[email protected]",
  "firstName": "Test",
  "lastName": "User"
  }
  }

🧪 Tests

  • Integration tests via Testcontainers (Kafka + MySQL)
  • Verify Saga flow: CREATE → INVENTORY_CONFIRMED → PAYMENT → ORDER_COMPLETED
  • Idempotency, Outbox, and TTL handling

🐳 Running Locally

git clone https://github.com/Andrij72/order-service.git
cd order-service
docker-compose -f docker-compose.local.yml up -d
./mvnw spring-boot:run

⚠️ Failure Handling

  • Inventory insufficient → INVENTORY_REJECTED → order CANCELLED
  • Reservation TTL expired → INVENTORY_EXPIRED → order CANCELLED
  • Payment failed → PAYMENT_FAILED → compensation: INVENTORY_CANCELLED

👨‍💻 Author

Andrii Kulynch Microservices, Kafka, Saga, Outbox, Spring Boot 📅 Version: 3.0

About

Standalone microservice extracted from MicroserviceGrid-DDD. Handles order lifecycle: creation, cancellation, payment, inventory reservation. Saga + Outbox patterns ensure reliable event-driven processes. Built with Java 21, Spring Boot 3, Kafka, MySQL.

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors