Skip to content

gyaan/aurelius

Repository files navigation

Distributed E-Commerce Microservices

A production-grade Java 21 / Spring Boot 3.4.x microservices project demonstrating synchronous (Feign + Resilience4j) and asynchronous (Kafka) inter-service communication, Redis caching, distributed tracing, and API Gateway routing.


Architecture Overview

                        ┌─────────────────────┐
                        │     API Gateway      │  :8080
                        │  (Spring Cloud GW)   │
                        └──────────┬──────────┘
                 ┌─────────────────┼──────────────────┐
                 ▼                 ▼                   ▼
        ┌──────────────┐  ┌──────────────┐  ┌──────────────────┐
        │ Order Service│  │  Inventory   │  │Payment / Notif.  │
        │    :8081     │  │   Service    │  │  Service :8083   │
        │              │  │    :8082     │  │  Service :8084   │
        └──────┬───────┘  └──────┬───────┘  └────────┬─────────┘
               │  Feign(sync)    │                    │
               └────────────────►│                    │
               │                 │            Kafka consumers
               │  Kafka(async)   │            ORDER_PLACED topic
               └─────────────────────────────────────►│
                                 │
        ┌────────────────────────────────────────────────────────┐
        │               Infrastructure (Docker)                  │
        │  PostgreSQL×3  │  Redis  │  Kafka+ZK  │  Zipkin        │
        └────────────────────────────────────────────────────────┘

Communication Patterns

Flow Protocol Detail
Client → Services HTTP Via API Gateway routes
Order → Inventory Feign (REST) Synchronous stock check with Resilience4j circuit breaker
Order → Payment/Notification Kafka Async ORDER_PLACED event, fire-and-forget
Payment DLQ Kafka @RetryableTopic (4 attempts) + @DltHandler
Notification Java async CompletableFuture.allOf(email, sms).join()

Tech Stack

Layer Technology
Language Java 21 + Virtual Threads (spring.threads.virtual.enabled=true)
Framework Spring Boot 3.4.3, Spring Cloud 2024.0.1
Sync comms Spring Cloud OpenFeign + Resilience4j Circuit Breaker
Async comms Apache Kafka (ORDER_PLACED topic)
Persistence PostgreSQL 16 via Spring Data JPA (3 separate DBs)
Caching Redis 7.2 via Spring Cache (GenericJackson2JsonRedisSerializer)
Tracing Micrometer Tracing (Brave) + Zipkin
Concurrency @Version optimistic locking, @Retryable, CompletableFuture
Gateway Spring Cloud Gateway (Netty, reactive — no servlet web starter)
Build Maven Multi-Module (parent + 5 child modules)
Infra Docker Compose

Project Structure

java_microservice/
├── pom.xml                        ← parent (Spring Boot 3.4.3, Cloud 2024.0.1, Java 21)
├── docker-compose.yml             ← all infrastructure services
│
├── order-service/          :8081
│   └── src/main/java/com/ecommerce/orderservice/
│       ├── config/         FeignConfig, KafkaProducerConfig, RedisConfig
│       ├── controller/     OrderController
│       ├── dto/            OrderRequest, OrderResponse, InventoryResponse
│       ├── entity/         Order
│       ├── event/          OrderPlacedEvent
│       ├── exception/      InsufficientStockException, GlobalExceptionHandler
│       ├── feign/          InventoryFeignClient, InventoryFeignFallback
│       ├── repository/     OrderRepository
│       └── service/        OrderService  (@CircuitBreaker)
│
├── inventory-service/      :8082
│   └── src/main/java/com/ecommerce/inventoryservice/
│       ├── config/         RedisConfig
│       ├── controller/     InventoryController
│       ├── dto/            InventoryResponse, StockCheckRequest
│       ├── entity/         Inventory  (@Version optimistic lock)
│       ├── exception/      OutOfStockException, GlobalExceptionHandler
│       ├── repository/     InventoryRepository
│       └── service/        InventoryService  (@Cacheable, @Retryable)
│
├── payment-service/        :8083
│   └── src/main/java/com/ecommerce/paymentservice/
│       ├── config/         KafkaConsumerConfig
│       ├── dto/            PaymentRecord
│       ├── entity/         Payment
│       ├── event/          OrderPlacedEvent
│       ├── exception/      PaymentProcessingException
│       ├── listener/       OrderEventListener  (@RetryableTopic, @DltHandler)
│       ├── repository/     PaymentRepository
│       └── service/        PaymentService
│
├── notification-service/   :8084
│   └── src/main/java/com/ecommerce/notificationservice/
│       ├── config/         AsyncConfig  (ThreadPoolTaskExecutor)
│       ├── dto/            NotificationPayload
│       ├── event/          OrderPlacedEvent
│       ├── listener/       NotificationListener
│       └── service/        NotificationService  (CompletableFuture.allOf)
│
└── api-gateway/            :8080
    └── src/main/java/com/ecommerce/apigateway/
        └── ApiGatewayApplication.java

Prerequisites

Tool Version Install
Java 21 brew install openjdk@21
Maven 3.9+ brew install maven
Docker Desktop 4.x+ docker.com

Important: Lombok is incompatible with Java 25. Always use Java 21 to build.

Add to ~/.zshrc:

export JAVA_HOME="/opt/homebrew/opt/openjdk@21/libexec/openjdk.jdk/Contents/Home"
export PATH="/opt/homebrew/opt/openjdk@21/bin:$PATH"

Quick Start

1. Start infrastructure

cd java_microservice
docker compose up -d
docker compose ps        # all should show (healthy)

Infrastructure ports:

Service Host Port
order-db (PostgreSQL) 5435
inventory-db (PostgreSQL) 5433
payment-db (PostgreSQL) 5434
Redis 6379
Kafka 9092
Zipkin 9411

Note: order-db uses port 5435 (not 5432) to avoid conflict with any locally-installed PostgreSQL.

2. Build all modules

mvn clean install -DskipTests

3. Start services (in order)

Open 5 separate terminals, or run them in the background:

# Terminal 1 — inventory first (order-service calls it via Feign)
java -jar inventory-service/target/inventory-service-1.0.0-SNAPSHOT.jar

# Terminal 2
java -jar order-service/target/order-service-1.0.0-SNAPSHOT.jar

# Terminal 3
java -jar payment-service/target/payment-service-1.0.0-SNAPSHOT.jar

# Terminal 4
java -jar notification-service/target/notification-service-1.0.0-SNAPSHOT.jar

# Terminal 5
java -jar api-gateway/target/api-gateway-1.0.0-SNAPSHOT.jar

4. Seed test inventory

docker exec inventory-db psql -U postgres -d inventory_db -c "
  INSERT INTO inventory (sku_code, quantity, version)
  VALUES ('SKU-LAPTOP-001', 50, 0),
         ('SKU-PHONE-002',   5, 0),
         ('SKU-EMPTY-003',   0, 0)
  ON CONFLICT (sku_code) DO NOTHING;
"

5. Verify all services healthy

curl http://localhost:8080/actuator/health   # gateway
curl http://localhost:8081/actuator/health   # order
curl http://localhost:8082/actuator/health   # inventory
curl http://localhost:8083/actuator/health   # payment
curl http://localhost:8084/actuator/health   # notification

API Reference

API Gateway routes

All requests go through the gateway on port 8080.

Route Target Method
/api/orders/** order-service :8081 POST
/api/inventory/** inventory-service :8082 GET
/api/payments/** payment-service :8083
/api/notifications/** notification-service :8084

Place an order

POST /api/orders
Content-Type: application/json
{
  "skuCode": "SKU-LAPTOP-001",
  "quantity": 2,
  "price": 999.99,
  "customerEmail": "alice@example.com",
  "customerPhone": "+91-9876543210"
}

201 Created:

{
  "id": 1,
  "orderNumber": "5a4af749-0e5a-49e5-bc7a-34dc52e540ec",
  "skuCode": "SKU-LAPTOP-001",
  "quantity": 2,
  "price": 999.99,
  "status": "PLACED",
  "createdAt": "2026-02-21T12:27:51.410159"
}

409 Conflict (out of stock):

{
  "title": "Insufficient Stock",
  "status": 409,
  "detail": "Insufficient stock for SKU: SKU-EMPTY-003"
}

Check inventory

GET /api/inventory/check?skuCode=SKU-LAPTOP-001&quantity=2
{
  "skuCode": "SKU-LAPTOP-001",
  "inStock": true,
  "availableQuantity": 50
}

Observability

Zipkin (distributed tracing)

Open http://localhost:9411 in a browser. Traces are sampled at 100% (probability: 1.0).

All service logs include trace/span IDs:

INFO [order-service,69995818979df9c820a3bc44718b825f,28359cae5ffcffcc] ...

Actuator endpoints

Each service exposes:

  • /actuator/health
  • /actuator/info
  • /actuator/metrics
  • /actuator/prometheus

Known Issues & Notes

Issue Root Cause Fix Applied
Lombok fails on Java 25 TypeTag::UNKNOWN — Lombok incompatible Use Java 21 (openjdk@21)
Feign fallback= ignored FeignCachingInvocationHandlerFactory bypasses CB in Spring Cloud 2024 Switched to @CircuitBreaker on OrderService.placeOrder()
order-db port 5435 Local PostgreSQL occupies 5432 docker-compose.yml maps 5435→5432 for order-db
Redis 500 error InventoryResponse not Serializable Added RedisConfig (Jackson serializer) to inventory-service

About

Distributed e-commerce backend built with Java 21, Spring Boot 3.4, Spring Cloud Gateway, Kafka, Redis, and PostgreSQL — Maven multi-module microservices with circuit breakers, distributed tracing, and optimistic locking.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages