Fluxo order.created

Consistência eventual na prática

Você implementa estados transitórios de pedido e deixa a API honesta sobre o processamento assíncrono.

Avançado 45 min 25 pontos Leitura 0%

Nesta aula você vai

  • Modelar estados de pedido em processamento assíncrono
  • Expor consulta de status compatível com consistência eventual
  • Implementar atualização de estado após retorno do pagamento

Consistência eventual na prática

Objetivos

  • Modelar estados de pedido em processamento assíncrono
  • Expor consulta de status compatível com consistência eventual
  • Implementar atualização de estado após retorno do pagamento

Pré-requisitos

  • Fluxo order.created já publicado/consumido
  • order-service com criação de pedidos
  • payment-service processando eventos

Conceito

Consistência eventual não é bug: é escolha arquitetural. Em sistemas orientados a eventos, a criação do pedido e a confirmação de pagamento acontecem em momentos diferentes. Se a API esconde isso, o usuário recebe informação incorreta e o time perde rastreabilidade.

O correto é modelar estados transitórios explícitos (PENDING_PAYMENT, PAID, PAYMENT_FAILED) e atualizar o pedido quando o evento de pagamento chegar. Assim, o produto comunica o estado real do negócio sem prometer sincronismo inexistente.

Nesta aula, você implementa essa máquina de estados de ponta a ponta: criação de pedido, consulta de status e atualização assíncrona no order-service.

Estrutura de arquivos

services/order-service/app/repository/order_repository.py
services/order-service/app/api/orders.py
services/order-service/app/consumers/payment_result_consumer.py
services/payment-service/internal/publishers/payment_result_publisher.go
contracts/events/payment-approved.v1.json
contracts/events/payment-failed.v1.json

Passo a passo

  1. Definir estados no order_repository.py
class OrderRepository:
    _db = {}

    def save(self, order: dict):
        self._db[order["id"]] = order
        return order

    def get(self, order_id: str):
        return self._db.get(order_id)

    def update_status(self, order_id: str, status: str):
        if order_id in self._db:
            self._db[order_id]["status"] = status
  1. Retornar estado real no endpoint de consulta
@router.get("/{order_id}")
def get_order(order_id: str):
    order = service.get_by_id(order_id)
    if not order:
        raise HTTPException(status_code=404, detail="pedido não encontrado")
    return {
        "id": order["id"],
        "customer_id": order["customer_id"],
        "total_amount": order["total_amount"],
        "status": order["status"]
    }
  1. Atualizar estado do pedido com eventos de pagamento
# payment_result_consumer.py
def handle_payment_approved(event: dict):
    repo.update_status(event["orderId"], "PAID")

def handle_payment_failed(event: dict):
    repo.update_status(event["orderId"], "PAYMENT_FAILED")
  1. Publicar resultado no payment-service (Go)
type PaymentResultEvent struct {
  EventID   string `json:"eventId"`
  OrderID   string `json:"orderId"`
  Status    string `json:"status"`
  Reason    string `json:"reason,omitempty"`
  OccurredAt string `json:"occurredAt"`
}

Como testar

  1. Subir stack:
docker compose -f infra/docker-compose.yml up --build -d
  1. Criar pedido:
ORDER=$(curl -s -X POST http://localhost:8000/orders \
  -H "Content-Type: application/json" \
  -d '{"customer_id":"cli-500","total_amount":120.00,"currency":"BRL"}')
echo "$ORDER"
  1. Consultar status logo após criação:
curl -s http://localhost:8000/orders/<ORDER_ID>

Esperado inicial: status: "PENDING_PAYMENT".

  1. Após processamento do payment, consultar novamente:
curl -s http://localhost:8000/orders/<ORDER_ID>

Esperado final: status: "PAID" ou status: "PAYMENT_FAILED".

Dicas de projeto

  • Use nomes de status legíveis para produto e suporte.
  • Defina SLA para tempo máximo em PENDING_PAYMENT.
  • Mantenha transição de estado só por evento de domínio.
  • Logue cada mudança de status com correlationId.

Erros comuns

  • Retornar "pedido pago" no POST /orders sem confirmação.
  • Atualizar status por timer em vez de evento.
  • Não tratar pedidos presos em pendência.
  • Confundir estado de UI com estado de domínio.

Resumo

Você implementou consistência eventual de forma explícita no domínio e na API. O fluxo de pedidos agora comunica estado real ao usuário e prepara o terreno para notificação de pagamento.