Backend · Sistemas distribuídos

Resilient Transaction API

API transacional com idempotência e resiliência a falhas, validada em lab AWS temporário e benchmark reproduzível em Docker local.

Visitar site

Problema

Operações transacionais precisam lidar com concorrência, respostas externas ambíguas e dependências que podem falhar. Este projeto explora essas propriedades em uma API de pagamentos, com código, testes e medições públicos; não representa um sistema financeiro em produção.

Arquitetura e decisões

O fluxo principal é HTTP → autenticação service-to-service → rate limiting → validação → claim de idempotência → resiliência do provider → persistência → resposta.

  • PostgreSQL é a fonte de verdade. A Idempotency-Key é reivindicada atomicamente no banco. Os resultados distinguem claim novo, replay concluído, conflito de fingerprint e operação em processamento. A transação de banco não fica aberta durante a chamada externa ao provider.
  • Redis é degradável. É usado para cache-aside e rate limiting distribuído; não é fonte de verdade. Durante indisponibilidade, leituras continuam pelo PostgreSQL, com custo de timeout e menor proteção de rate limiting.
  • O provider pode falhar. Há timeout, retry limitado, exponential backoff, jitter e circuit breaker, com classificação de falhas definitivas, transitórias e ambíguas. Repetir pode aumentar latência e custo; uma falha ambígua não prova que a operação externa deixou de acontecer.
  • Operação observável. A API registra X-Request-Id, logs JSON redigidos, métricas Prometheus em /metrics, liveness e readiness. O encerramento trata SIGTERM e drena requests em andamento.

O stack local usa PostgreSQL, Redis, migração e fake provider via Compose. A imagem Docker é multi-stage, executa Bun como PID 1 e usuário não-root, com filesystem read-only, capabilities removidas e no-new-privileges.

Benchmark local

Baseline executada em containers na mesma máquina Linux x86_64, com 4 vCPUs e aproximadamente 3,8 GiB de RAM; Bun 1.4.2, PostgreSQL 15.19, Redis 7.2.16, Docker e fake provider. Cada cenário principal teve três execuções de 300 requests, concorrência 25, após aquecimento. São medições locais, não uma previsão de throughput de produção ou AWS.

Cenário p50 p95 p99 Throughput
GET cache hit 3.065 ms 4.818 ms 5.833 ms 7,524.7 req/s
GET cache miss 7.301 ms 10.210 ms 11.706 ms 3,289.3 req/s
GET replay persistente 6.712 ms 9.696 ms 11.513 ms 3,502.0 req/s
POST novo 20.871 ms 31.805 ms 35.610 ms 1,129.9 req/s

Ensaios controlados complementares: provider com 100 ms artificiais teve p50 109.281 ms e p95 149.119 ms; retry 503 → success concluiu em 626.263 ms, com um retry registrado. Com 20 POSTs simultâneos usando a mesma key, houve uma criação, quatro replays concluídos e 15 respostas de operação em processamento. Com Redis indisponível, os requests observados retornaram 200; três runs tiveram p50 entre 192.934 ms e 753.890 ms, uma variação que impede resumir o fallback em uma única latência típica. O teste de rate limit observou 429 com Retry-After ao exceder o limite configurado.

AWS validation lab temporário

Em us-east-1, Terraform provisionou 35 recursos para um lab temporário real. A arquitetura exercitada foi HTTPS/ACM → ALB → ECS/Fargate → Bun API → RDS PostgreSQL privado / ElastiCache Redis privado, com Secrets Manager, CloudWatch Logs, ECR e IAM como serviços de apoio. A API e o fake provider determinístico rodaram como containers da mesma task; uma task Fargate one-off executou as migrations.

Para reduzir o custo do lab, as tasks ficaram em public subnets com public IP, mas aceitaram tráfego inbound somente do ALB. RDS e Redis permaneceram privados. Essa foi uma escolha temporária de laboratório, não a topologia preferida para produção: essa mantém as tasks ECS em private subnets com egress deliberado por NAT Gateway e/ou VPC endpoints.

Verificação no lab AWS Evidência observada
Target do ALB e /health/ready healthy; HTTP 200 ready
POST autenticado e replay com a mesma Idempotency-Key HTTP 201; depois HTTP 200 com a mesma transação
Cache-aside cache_miss_total 1; cache_hit_total 1
Rate limiter 5 respostas HTTP 200; a 6ª recebeu HTTP 429
CloudWatch Logs Logs estruturados, request IDs e RATE_LIMIT_EXCEEDED
Serviço ECS ao final do smoke test desired 1, running 1, pending 0, failed 0

O deploy também revelou dois ajustes necessários: o RDS recusou backup retention de 7 dias no ambiente usado, então foi configurado para 1 dia; e o PostgreSQL no RDS exigiu TLS, então a DATABASE_URL recebeu sslmode=require.

O ciclo foi fechado após os testes: ECR esvaziado, terraform destroy removeu os 35 recursos e o Terraform state ficou vazio. A auditoria final não encontrou ECS, RDS, ElastiCache, ALB, ECR ou CloudWatch Logs; o CNAME público foi removido. O ALB e todos os demais recursos Terraform do lab foram destruídos. O certificado público ACM foi mantido intencionalmente para possível reutilização; os secrets ficaram agendados para exclusão.

Este foi um lab de validação temporário e não representa um ambiente de produção. O serviço usou desired=1: não foi demonstrada alta disponibilidade nem compartilhamento do rate limiter entre múltiplas réplicas.

Validação local e limites

O relatório de validação containerizada local registra 164 testes, 662 assertions, zero falhas — incluindo 20 integrações PostgreSQL e 11 Redis — e um shutdown real via SIGTERM durante request: a request terminou, o processo saiu sem SIGKILL e o encerramento levou cerca de 2,31 s.

  • O benchmark é local, específico ao hardware descrito, executado com fake provider e cliente/servidor no mesmo host; não representa produção, AWS ou múltiplas réplicas. O lab AWS não foi usado para medir benchmark.
  • Não há garantia exactly-once. O resultado externo ainda depende de o provider respeitar a mesma chave de idempotência.
  • Redis fail-open mantém parte do serviço disponível, mas reduz a proteção de rate limiting durante outage; timeouts podem elevar bastante a latência.
  • O circuit breaker é local ao processo, não coordenado entre réplicas.
  • O fake provider determinístico do lab não valida a integração com um provedor de pagamentos externo.
  • O lab de uma task não demonstra alta disponibilidade, comportamento com múltiplas réplicas ou rate limiting compartilhado entre elas.
  • A topologia temporária usou tasks em subnets públicas. Ela não valida a topologia production-preferred com tasks ECS privadas.

Evidências

Voltar aos projetos

VAMOS CONVERSAR

Bons produtos começam com uma boa conversa.

Oportunidades profissionais, parcerias ou uma conversa sobre software, engenharia e IA aplicada.

Conectar no LinkedIn