Lab

Food Delivery Lab: Order -> Payment -> Dispatch (with O11y)

Projeto exemplo: fluxo de pedido de delivery com saga, idempotência, eventos e observabilidade (logs + traces).

#system-design
#aws
#observability
#o11y
#idempotency

Skills: distributed-systems, event-driven-architecture, telemetry, idempotency, reliability

Food Delivery Lab

Este lab documenta um sistema de delivery (tipo iFood/Uber Eats) para demonstrar como usar o Engineering Lab com:

  • diagramas (arquitetura e sequência)
  • logs com correlação (trace_id, order_id)
  • traces estilo Jaeger (spans, atributos, árvore)

Meta do lab: mostrar como eu penso, não só o resultado.


Context

Quero um fluxo realista: criar pedido, reservar pagamento, confirmar, enviar para despacho. Esse tipo de domínio é ótimo para mostrar:

  • consistência eventual e saga
  • idempotência
  • filas e retries
  • observabilidade ponta a ponta

Thought process (como eu cheguei nessa arquitetura)

  1. Escolha do núcleo: o "Order Service" é o agregador do fluxo (estado do pedido).
  2. Pagamento é assíncrono: mesmo com “reserva”, existe latência e falhas; então a confirmação volta por evento.
  3. Dispatch é desacoplado: o matching de entregador precisa escalar e variar, então não fica no request síncrono.
  4. Idempotência é obrigatória: requisições duplicadas (mobile) e retries (fila) são parte do mundo real.
  5. O11y é primeiro cidadão: eu quero conseguir responder “onde dói?” em 2 minutos:
    • qual serviço falhou?
    • onde foi lento?
    • quantos retries?
    • qual pedido afetado?

Architecture (Flowchart)

Diagram

Node metadata (fallback MVP)


Sequence (Happy path + async confirmation)

Diagram


Observability plan (o que eu quero enxergar)

  • Trace único por pedido: do POST /orders até CourierAssigned.
  • Correlação no log: trace_id, span_id, order_id, idempotency_key.
  • Pontos críticos:
    • pagamento (latência externa + falhas)
    • consumo de eventos (retries, DLQ)
    • dispatch (matching pode ser pesado)
  • Métricas mínimas:
    • orders_created_total
    • payment_authorize_latency_ms (p95/p99)
    • event_consumer_retries_total
    • dlq_messages_total

Logs (mock realista)

Log Console

TimeLevelSourceMessage
2026-03-02T19:10:12.120Z
INFO
api-gatewayrequest_in
2026-03-02T19:10:12.145Z
INFO
order-servicecreate_order_received
2026-03-02T19:10:12.168Z
INFO
order-servicedb_tx_committed
2026-03-02T19:10:12.590Z
INFO
event-busdelivered_event
2026-03-02T19:10:12.602Z
INFO
payment-serviceauthorize_payment_start
2026-03-02T19:10:13.248Z
WARN
payment-serviceprovider_timeout_retrying
2026-03-02T19:10:13.910Z
INFO
payment-serviceauthorize_payment_success
2026-03-02T19:10:14.020Z
INFO
event-buspublished_event
2026-03-02T19:10:14.082Z
INFO
order-servicepayment_authorized_received
2026-03-02T19:10:14.104Z
INFO
order-serviceorder_confirmed
2026-03-02T19:10:14.350Z
INFO
dispatch-servicecourier_matching_completed
2026-03-02T19:10:14.410Z
INFO
notification-servicepush_sent

Trace (mock estilo Jaeger)

Trace Viewer

Span Tree

Detalhes

Span

HTTP POST /orders

Service

api-gateway

Duration

48ms

Attributes

http.methodPOST
http.route/orders
http.status_code202
client.idmlb-user-9182
idempotency_keyidem_7f8b2a

Trade-offs (o que eu aceitei)

  • Consistência eventual: o cliente recebe 202 Accepted e consulta status depois.
  • Outbox adiciona complexidade, mas evita o pior bug: pedido criado sem evento (ou evento sem pedido).
  • Pagamento async melhora resiliência e escala, mas exige bom design de estados.

Next iteration (o que eu faria depois)

  • Adicionar DLQ + replay para PaymentAuthorized e OrderConfirmed.
  • Métricas com SLO:
    • % orders confirmed em < 3s
    • % payment retries
  • Traces reais (export OTel) e importar como JSON (ao invés de mock).