| Requirement | Mechanism | Verification |
|---|---|---|
Load balancer |
Nginx round-robin | /whoami alternates instances |
API |
Spring Cloud Gateway | all traffic via :8000 |
Multiple instances |
event-service-1/-2 | both healthy, both serve |
Async communication |
RabbitMQ topic exchange | order.confirmed -> notification |
Concurrency control |
atomic DB UPDATE | 2nd reserve on qty=1 -> 409 |
Resilience |
Resilience4j CB+retry | breaker opens at failureRate=1.0 |
Idempotency |
gateway key + consumer PK + status guard | kill-test: one charge/ticket/email |
Observability |
JSON logs + Prometheus + Grafana | dashboard panels + structured logs |
Mocked payment/email |
standalone mock + log/DB notification | admin/mode flips, /notifications |
docker compose up --build
curl http://localhost:8000/whoami
curl http://localhost:8000/whoami
curl -X POST http://localhost:8000/users -H "Content-Type: application/json" -d "{\"email\":\"leo@test.com\",\"name\":\"Leonardo\"}"
curl -X POST http://localhost:8000/events -H "Content-Type: application/json" -d "{\"name\":\"Show D\",\"eventDate\":\"2026-11-01T20:00:00\",\"price\":120.00,\"availableQuantity\":3}"
curl http://localhost:8000/events
curl -X POST http://localhost:8000/orders -H "Content-Type: application/json" -d "{\"userId\":1,\"eventId\":1}"
curl -X POST http://localhost:8000/orders/1/pay -H "Content-Type: application/json" -d "{\"paymentMethod\":\"CREDIT_CARD\",\"amount\":120.00}"
curl http://localhost:8000/notifications
100% failure
curl -X POST http://localhost:8090/admin/mode -H "Content-Type: application/json" -d "{\"failureRate\":1.0}"
watch retries then breaker opening in logs
curl -X POST http://localhost:8000/orders/1/pay -H "Content-Type: application/json" -d "{\"paymentMethod\":\"CREDIT_CARD\",\"amount\":120.00}"
recover
curl -X POST http://localhost:8090/admin/mode -H "Content-Type: application/json" -d "{\"failureRate\":0.0}"
curl -X POST http://localhost:8000/events -H "Content-Type: application/json" -d "{\"name\":\"Soldout\",\"eventDate\":\"2026-12-01T20:00:00\",\"price\":50.00,\"availableQuantity\":1}"
curl -X POST http://localhost:8000/orders -H "Content-Type: application/json" -d "{\"userId\":1,\"eventId\":1}"
curl -X POST http://localhost:8000/orders -H "Content-Type: application/json" -d "{\"userId\":1,\"eventId\":1}"
http://localhost:8000 -> API Gateway (all app traffic)
http://localhost:9090/targets -> Prometheus (confirm all targets UP)
http://localhost:3000 -> Grafana (admin/admin)
http://localhost:15672 -> RabbitMQ management (tickets/tickets)
docker compose psㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ ㅤ# status of all containers
docker compose logs -f order-serviceㅤ ㅤㅤ# follow one service's logs
docker compose logs -f payment-gateway-mock
docker compose downㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ # stop everything
docker compose down -vㅤㅤㅤㅤㅤㅤㅤ ㅤ ㅤ # stop + wipe volumes (fresh DB)
Grafana -> Dashboards -> New -> Add visualization -> Select Prometheus -> Paste The Query -> Set a Title -> Apply
rate(http_server_requests_seconds_count[1m])
histogram_quantile(0.95, rate(http_server_requests_seconds_bucket[1m]))
rate(http_server_requests_seconds_count{status=~"5.."}[1m])
tickets_sold_total
a client fires a payment, the network drops mid-flight (client never sees the response), the client retries with the same key; and the system ends with exactly one charge and one ticket.
set up fresh order
curl -X POST http://localhost:8000/events -H "Content-Type: application/json" -d "{\"name\":\"Idem Test\",\"eventDate\":\"2026-12-20T20:00:00\",\"price\":90.00,\"availableQuantity\":5}"
curl -X POST http://localhost:8000/orders -H "Content-Type: application/json" -d "{\"userId\":1,\"eventId\":1}"
make the gateway slow so you have time to kill the request
curl -X POST http://localhost:8090/admin/mode -H "Content-Type: application/json" -d "{\"latencyMs\":8000}"
fire the payment, then hit Ctrl+C after ~2 seconds; client abandons, but the charge may have landed
curl -X POST http://localhost:8000/orders/1/pay -H "Content-Type: application/json" -d "{\"paymentMethod\":\"CREDIT_CARD\",\"amount\":90.00}"
^C
Reset latency and retry the exact same payment (same order -> same idempotency key):
curl -X POST http://localhost:8090/admin/mode -H "Content-Type: application/json" -d "{\"latencyMs\":100}"
curl -X POST http://localhost:8000/orders/1/pay -H "Content-Type: application/json" -d "{\"paymentMethod\":\"CREDIT_CARD\",\"amount\":90.00}"
Now prove the end state; exactly one of everything:
order is CONFIRMED, not double-processed
curl http://localhost:8000/orders/1
exactly one email
curl http://localhost:8000/notifications
inventory decremented exactly once (started at 5, should be 4)
curl http://localhost:8000/events