Skip to content

Latest commit

 

History

5 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Distributed Task Queue System

A production-style asynchronous task processing system built with Java 17, Spring Boot, RabbitMQ, MySQL, Docker, and Maven.

The system accepts background jobs through REST APIs, persists task state in MySQL, publishes jobs to RabbitMQ, and processes them asynchronously using scalable worker services.

🚀 Portfolio Case Study

Synchronous APIs are not ideal for slow or failure-prone operations such as sending emails, generating reports, or delivering notifications.

This project solves that problem using a producer-worker architecture:

  • The Producer Service accepts and validates task requests.
  • MySQL stores task state, retry information, and audit logs.
  • RabbitMQ acts as the message broker and buffers background work.
  • Worker Services consume and process tasks asynchronously.
  • Docker Compose runs the complete distributed system locally.

The project also demonstrates production-oriented backend patterns including:

  • Manual message acknowledgements
  • Retry mechanisms with exponential backoff
  • Dead-letter queues
  • Horizontal worker scaling
  • Idempotent task submission
  • API rate limiting
  • Priority-based message processing
  • Health checks
  • Audit logging

🏗️ Architecture

                     ┌─────────────────┐
                     │     Client      │
                     │  REST / Postman │
                     └────────┬────────┘
                              │
                              ▼
                  ┌──────────────────────┐
                  │   Producer Service   │
                  │     Spring Boot      │
                  └──────────┬───────────┘
                             │
                ┌────────────┴────────────┐
                │                         │
                ▼                         ▼
        ┌───────────────┐        ┌─────────────────┐
        │     MySQL     │        │    RabbitMQ     │
        │ Task State +  │        │ Exchange/Queues │
        │  Audit Logs   │        └────────┬────────┘
        └───────────────┘                 │
                                          ▼
                              ┌─────────────────────┐
                              │    Worker Service   │
                              │                     │
                              │ ┌─────┐ ┌─────┐     │
                              │ │ W1  │ │ W2  │ ... │
                              │ └─────┘ └─────┘     │
                              └──────────┬──────────┘
                                         │
                                         ▼
                              ┌─────────────────────┐
                              │ Retry / DLQ Flow    │
                              └─────────────────────┘

🛠️ Tech Stack

Technology Purpose
Java 17 Backend development
Spring Boot REST APIs and application framework
Spring Data JPA Database persistence
Hibernate ORM
RabbitMQ Message broker
MySQL Task state and audit persistence
Docker Containerization
Docker Compose Local distributed environment
Maven Build and dependency management

✨ Key Features

Core Features

  • REST-based task submission
  • EMAIL, REPORT, and NOTIFICATION task types
  • Asynchronous task processing
  • RabbitMQ-based message routing
  • MySQL task persistence
  • Multiple worker instances
  • Manual message acknowledgements
  • Task status tracking
  • Audit logging

Reliability

  • Retry mechanism
  • Exponential backoff
  • Dead-letter queue handling
  • Failure tracking
  • Manual ACK/NACK flow
  • Persistent task state

Production-Style Controls

  • Idempotency keys
  • Fixed-window API rate limiting
  • RabbitMQ message priorities
  • Health check endpoints
  • Dockerized deployment
  • Horizontal worker scaling

📌 Project Phases

The project was implemented incrementally:

  • Phase 1 — Producer Service
  • Phase 2 — Worker Service
  • Phase 3 — Multi-worker Load Balancing
  • Phase 4 — Retry & Dead-Letter Queue
  • Phase 5 — Dockerized Deployment
  • Phase 6 — Idempotency, Rate Limiting & Priority Queues

Phase 1 — Producer Service

The Producer Service provides the REST entry point for task submission.

What We Built

  • POST /api/tasks
  • Request DTO validation
  • EMAIL, REPORT, and NOTIFICATION jobs
  • UUID-based task creation
  • MySQL persistence
  • QUEUED task status
  • RabbitMQ publishing
  • Direct exchange routing

Request Flow

Client
   │
   ▼
REST Controller
   │
   ▼
Task Service
   │
   ├──────────────► MySQL
   │                 │
   │                 └── Task = QUEUED
   │
   └──────────────► RabbitMQ
                         │
                         ▼
                       Queue

Why It Matters

Instead of keeping the HTTP request open while the task executes, the API quickly accepts the job and returns a response.

This provides:

  • Lower API latency
  • Better scalability
  • Decoupling between API and workers
  • Persistent task tracking

Interview Talking Point

The controller remains thin while the service layer contains the business logic. RabbitMQ provides asynchronous decoupling between request handling and background processing.


Phase 2 — Worker Service

The Worker Service processes tasks asynchronously from RabbitMQ.

What We Built

  • @RabbitListener consumers
  • EMAIL processor
  • REPORT processor
  • NOTIFICATION processor
  • Manual acknowledgements
  • Success/failure handling
  • Task status updates
  • Audit logs

Processing Flow

RabbitMQ
    │
    ▼
Worker
    │
    ▼
PROCESSING
    │
    ▼
Task Processor
   / \
  /   \
Success Failure
  │       │
  ▼       ▼
 ACK    Retry/DLQ

Why It Matters

Slow or failure-prone work is removed from the synchronous HTTP request path.

Multiple workers can process tasks concurrently, improving throughput and resilience.

Interview Talking Point

Manual acknowledgements make message processing explicit. A successful task is ACKed, while failed tasks can enter the retry or dead-letter flow.


Phase 3 — Load Balancing

This phase demonstrates horizontal worker scaling.

RabbitMQ distributes messages from the same queue across multiple consumers.

Demo

Start the system

docker compose up --build -d

Scale the workers

docker compose up --scale task-worker=3 -d

Run the load-balancing demo

chmod +x scripts/phase3-load-balancing-demo.sh
./scripts/phase3-load-balancing-demo.sh

Watch worker logs

docker compose logs -f task-worker

What to Observe

Each worker logs its own workerId.

You should see tasks being processed by different worker containers.

With:

prefetch-count: 1

RabbitMQ limits each worker to one unacknowledged message at a time, helping achieve fairer dispatch.


Phase 4 — Retry & Dead-Letter Queue

Failed tasks are not immediately requeued.

Instead, retryable failures are published to a dedicated retry exchange and retry queue.

The retry queue uses message TTL + dead-lettering to delay the next processing attempt.

Failure Flow

                 ┌──────────────┐
                 │    Worker    │
                 └──────┬───────┘
                        │
                     Failure
                        │
                        ▼
                ┌───────────────┐
                │ Retry Exchange│
                └───────┬───────┘
                        │
                        ▼
                ┌───────────────┐
                │   Retry Queue │
                │      TTL      │
                └───────┬───────┘
                        │
                     Expired
                        │
                        ▼
                ┌───────────────┐
                │ Main Exchange │
                └───────┬───────┘
                        │
                        ▼
                    Main Queue

If the maximum retry count is exhausted:

Worker
  │
  ▼
Failure
  │
  ▼
Retries Remaining?
  │
 ┌┴─────────┐
 │          │
Yes         No
 │          │
 ▼          ▼
Retry       DLQ
           │
           ▼
      DEAD_LETTER

Why Delayed Retry Is Better Than Immediate Requeue

Immediate requeue can create a hot retry loop where the same failing task repeatedly consumes worker resources.

Delayed retries:

  • Reduce pressure on workers
  • Give dependencies time to recover
  • Avoid tight retry loops
  • Preserve failure history
  • Provide predictable retry behavior

Demo

Submit tasks using the built-in failure scenarios and monitor:

docker compose logs -f task-worker

Look for events such as:

FAILED
RETRY_SCHEDULED
DEAD_LETTERED

RabbitMQ Management UI can also be used to inspect retry queues and DLQ depth.


Phase 5 — Dockerized Deployment

The complete system runs through Docker Compose.

Components

Docker Compose
│
├── MySQL
├── RabbitMQ
├── Producer Service
└── Worker Service(s)

Start the Stack

chmod +x scripts/phase5-up.sh
./scripts/phase5-up.sh

By default, the script starts three worker replicas.

To change the number:

WORKER_REPLICAS=5 ./scripts/phase5-up.sh

Useful Commands

docker compose ps
docker compose logs -f task-producer
docker compose logs -f task-worker
docker compose down

Docker Compose Responsibilities

  • Starts MySQL
  • Initializes the database schema
  • Starts RabbitMQ with Management UI
  • Builds producer and worker images
  • Waits for healthy dependencies
  • Runs multiple worker containers
  • Provides a reproducible local environment

Phase 6 — Advanced Backend Engineering

The final phase adds production-style controls around task submission.

Idempotency

Each task can contain an idempotencyKey.

If the same key is submitted again, the existing task is returned instead of creating another task.

Example

{
  "type": "EMAIL",
  "payload": "{\"to\":\"user@example.com\",\"subject\":\"Welcome\"}",
  "idempotencyKey": "welcome-email-user-123"
}

Why Idempotency Matters

Clients may retry requests because of:

  • Network failures
  • Request timeouts
  • Frontend retries
  • Mobile connectivity issues

Without idempotency, the same operation could be executed multiple times.

For example:

Client
  │
  ├── Request ───────► Producer
  │
  │     Network timeout
  │
  └── Retry ─────────► Producer

The idempotency key allows the backend to recognize both requests as the same logical operation.


Rate Limiting

The Producer applies a fixed-window rate limit based on client IP.

When the limit is exceeded, the API returns:

429 Too Many Requests

Example

{
  "timestamp": "2026-08-22T12:00:00",
  "status": 429,
  "error": "Rate Limit Exceeded",
  "message": "Too many requests. Retry after 60 seconds.",
  "retryAfterSeconds": 60
}

Why Rate Limiting Matters

Rate limiting prevents a single client from generating excessive traffic and protects the producer from accidental bursts.


Priority Queues

RabbitMQ message priorities allow urgent tasks to be processed before lower-priority tasks that are waiting in the queue.

The producer sets the message priority using the task's priority field.

Example

{
  "type": "REPORT",
  "priority": 8,
  "maxRetries": 3
}

A higher priority value means the task receives higher processing preference while waiting in the queue.


🔌 API Examples

Submit a Task

curl -X POST http://localhost:8080/api/tasks \
  -H "Content-Type: application/json" \
  -d '{
    "type": "EMAIL",
    "payload": "{\"to\":\"user@example.com\",\"subject\":\"Welcome\"}",
    "priority": 8,
    "maxRetries": 3,
    "idempotencyKey": "welcome-email-user-123"
  }'

Check Task Status

curl http://localhost:8080/api/tasks/{taskId}

📮 Postman Collection

Import the following files into Postman:

postman/
├── DistributedTaskQueueSystem.postman_collection.json
└── DistributedTaskQueueSystem.postman_environment.json

The collection includes:

  • EMAIL task submission
  • REPORT task submission
  • NOTIFICATION task submission
  • Idempotency duplicate request
  • Worker health check
  • Task log inspection
  • Rate-limit burst demo

🧪 Testing the System

A typical end-to-end test looks like:

POST /api/tasks
       │
       ▼
Task persisted in MySQL
       │
       ▼
Published to RabbitMQ
       │
       ▼
Worker consumes message
       │
       ▼
Task → PROCESSING
       │
       ▼
Processor executes task
       │
    ┌──┴──┐
    │     │
 Success Failure
    │     │
    ▼     ▼
   ACK   Retry
          │
          ▼
       Eventually
        ┌───┴───┐
        │       │
      Success   DLQ

💡 Key Engineering Concepts Demonstrated

This project demonstrates practical backend engineering concepts including:

  • REST API design
  • DTO validation
  • Layered architecture
  • Spring Boot
  • Spring Data JPA
  • Hibernate
  • MySQL persistence
  • RabbitMQ exchanges and queues
  • Routing keys
  • Manual message acknowledgements
  • Consumer concurrency
  • Fair dispatch
  • Retry with exponential backoff
  • Dead-letter queues
  • Idempotency
  • Rate limiting
  • Priority queues
  • Audit logging
  • Health checks
  • Docker
  • Docker Compose
  • Horizontal scaling
  • Asynchronous processing
  • Event-driven architecture

📊 Project Highlights

Capability Implementation
API Layer Spring Boot REST APIs
Persistence MySQL + JPA/Hibernate
Messaging RabbitMQ
Processing Asynchronous workers
Scaling Multiple worker containers
Reliability Manual ACK + retry
Failure Handling DLQ
Retry Strategy TTL + dead-lettering
Duplicate Protection Idempotency keys
API Protection Rate limiting
Task Prioritization RabbitMQ priority queues
Deployment Docker Compose
Observability Task status + audit logs

🔗 Repository

GitHub:
https://github.com/anik-ug/distributed-task-queue-system


About

Production-style distributed task queue built with Java, Spring Boot, RabbitMQ, MySQL, and Docker, featuring async processing, retries, DLQ, idempotency, rate limiting, and horizontal worker scaling.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages