Vaxly is a scalable, distributed currency conversion microservices platform designed to handle real-time exchange rate requests with high reliability, low latency, and fault tolerance. While the core function is simple, the project demonstrates advanced backend engineering principles, including distributed systems, asynchronous workflows, event-driven architecture, and cloud-native design.
Vaxly consists of multiple microservices interacting via REST APIs, Redis caching, SQS queues, and a relational database, achieving high performance, scalability, and reliability.
-
Conversion Service (Client API)
- Handles client requests for currency conversion (e.g., USD → EUR).
- Implements a cache-first strategy:
- Checks Redis cache.
- Falls back to Historical Service.
- If missing, queries Aggregator Service for live rates.
- Enqueues new or frequently requested currency pairs to SQS for asynchronous processing.
-
Historical Service
- Stores historical currency rates in a database.
- Provides APIs to retrieve and update rates.
- Secured with Role-Based Access Control (RBAC).
-
Scheduler Service
- Periodically queries Redis for top N requested currency pairs.
- Checks in-flight flags and
last_refreshtimestamps to avoid duplicate work. - Enqueues eligible jobs to SQS and sets TTL flags to prevent stale processing.
-
Worker Service
- Consumes jobs from SQS.
- Fetches rates from Aggregator Service.
- Updates Redis and Historical Service.
- Clears
in-flightflags and updateslast_refreshtimestamps.
-
Aggregator Service
- Retrieves live rates from multiple third-party providers.
- Provides API endpoints for other services to query live data.
| Layer | Technology |
|---|---|
| Backend | Java 17, Spring Boot 3 |
| Persistence | PostgreSQL (AWS RDS), Spring Data JPA, Hibernate |
| Caching | Redis (AWS ElastiCache) |
| Messaging | AWS SQS (FIFO & Standard) |
| Infrastructure | AWS ECS Fargate, ALB, Secrets Manager |
| Infrastructure as Code | Terraform |
| Observability | Spring Actuator, Micrometer, Prometheus |
| Security | Spring Security (RBAC) |
- Cache-Aside / Lazy Loading: Conversion Service checks Redis before querying other services.
- Event-Driven Architecture: Scheduler → SQS → Worker enables asynchronous, decoupled processing.
- Distributed System Resilience: TTLs and in-flight flags prevent duplicate updates; failed jobs are retried.
- Role-Based Access Control (RBAC): Secure endpoints in Historical Service.
- Priority Queueing: High-priority (top N) vs low-priority pairs in SQS.
- Client requests a currency conversion (e.g., USD → EUR).
- Conversion Service checks Redis:
- Hit → returns cached rate.
- Miss → queries Historical Service → if unavailable, queries Aggregator Service.
- New or frequently requested pairs are enqueued to SQS.
- Scheduler Service periodically queries Redis for top N pairs and enqueues eligible jobs to SQS.
- Worker Service processes SQS jobs:
- Fetches live rates from Aggregator Service.
- Updates Redis and Historical Service.
- Clears
in-flightflags and updates timestamps.
- Aggregator Service ensures reliable, accurate live rates from multiple external providers.
┌───────────────────────┐
│ Client API │
│ (Conversion Service) │
└─────────┬─────────────┘
│ Request: USD/EUR
▼
┌─────────────┐
│ Redis │
└─────┬───────┘
Hit │ Miss
│ ▼
│ ┌─────────────┐
│ │ History DB │
│ └─────┬───────┘
│ Hit │ Miss
│ ▼
│ ┌───────────────┐
│ │ Aggregator │
│ │ Service │
│ └─────┬─────────┘
│ │ Fetch live 3rd-party rate
│ ▼
Return value│ ┌─────────────┐
to client │ │ Rate │
│ └─────┬──────┘
│ Enqueue new pair to SQS
│
▼
┌─────────────────────────┐
│ SQS Queue │
│ High-priority: top N │
│ Low-priority: others │
└─────┬───────────────────┘
│
▼
┌─────────────┐
│ Worker │
│ Service │
└─────┬───────┘
1. Set "in-flight" flag in Redis (TTL)
2. Fetch rate from Aggregator
3. Update Redis + History DB
4. Clear "in-flight" flag
5. Update "last_refresh" timestamp in Redis
▲
│
┌───────────┴──────────────┐
│ Scheduler Service │
│ (every N seconds) │
│ 1. Query Redis for top N|
│ most requested pairs │
│ 2. Check last_refresh & │
│ in-flight flags │
│ 3. Enqueue eligible pairs│
│ to SQS (high/low) │
└───────────────────────────┘