Pular para o conteúdo

apps/patterns/idempotency-layer

020 · Padrões Fundamentais · ≈ 5 min de estudo

Idempotency Layer

Garante que executar a mesma requisição várias vezes produz o mesmo efeito que executá-la uma única vez. O cliente envia um header Idempotency-Key; o servidor armazena a chave junto com a resposta na mesma transação. Retentativas com a mesma chave devolvem a resposta em cache, sem reprocessar.

passos
6
arquivos
6
teste
1
tecnologias
5
Infraestrutura realTypeScriptBunElysiaPostgreSQLDocker
Baixar cartão

Cenário

Um app de pagamentos envia um PIX. A resposta se perde por timeout de rede, e o cliente retenta a mesma requisição. Sem idempotência, o destinatário receberia o valor duas vezes. Com a Idempotency-Key, a segunda chamada devolve exatamente a resposta da primeira — o pagamento ocorre uma única vez.

Planta

Sequência
12/12
POST /payments (Idempotency-Key: K)1pg_advisory_xact_lock(K) + SELECT ... FOR UPDATE2vazio3INSERT payment + INSERT idempotency_keys (mesma tx)4201 Created (pagamento)5retentativa (timeout/rede) — mesma chave, mesmo payloadPOST /payments (Idempotency-Key: K)6SELECT ... WHERE key = K FOR UPDATE7resposta em cache8201 + X-Idempotent-Replay: true9mesma chave, payload DIFERENTE — erro de usoPOST /payments (Idempotency-Key: K, outro valor)10SELECT ... compara request_hash11422 Idempotency-Key já usada com payload diferente12ClienteServidorPostgreSQL
12

12 passos — reproduza para seguir o fluxo

Como funciona

6 passos

Mesma chave, efeito aplicado uma vez.

Esconde cada passo: lembre antes de tocar para revelar.

  1. 01

    O cliente gera uma Idempotency-Key única por operação e a envia em todas as retentativas daquela operação.

  2. 02

    O servidor calcula o request_hash (SHA-256 do corpo), trava a chave com pg_advisory_xact_lock — FOR UPDATE sozinho não trava linha que ainda não existe — e busca a chave com FOR UPDATE.

  3. 03

    Se a chave não existeGrava o pagamento e a chave com a resposta na mesma transação; falha técnica desfaz os dois e a retentativa roda de novo.

  4. 04

    Se a chave existe com o mesmo request_hash: devolve status e corpo gravados com X-Idempotent-Replay: true, sem reprocessar.

  5. 05

    Erro de negócio (valor acima de R$ 5.000,00 → 422) também é gravado: a retentativa recebe o mesmo erro.

  6. 06

    Se a chave existe com request_hash diferente: retorna 422 — a mesma chave foi reutilizada para outra operação (erro do cliente).

apps/patterns/idempotency-layer

6 arquivos

sql/

  • 01_schema.sqlschemaTabelas payments e idempotency_keys (chave, hash, resposta, expiração em 24h)

src/

  • idempotency_payment.tspaymentIdempotent: lock da chave, replay ou criação do pagamento na mesma transação
  • api_payment.tsPOST /payments (Elysia, porta 3000) com Idempotency-Key UUID obrigatória
  • config_payment.tsLê e valida PAYMENT_DATABASE_URL no boot
  • demo.tsdemoSobe a API e reenvia o mesmo PIX: retentativas, corrida, chave reutilizada e erro de negócio
  • idempotency_payment.test.tstesteIntegração com PostgreSQL real: um pagamento por chave, corrida, 422 e replay de erro

Executar · com Docker

  1. ./docker.sh up# sobe PostgreSQL
  2. cp .env.example .env# variáveis de ambiente
  3. bun install# dependências
  4. bun run demo# roda o cenário

Testes: bun run test.

Requisitos
BunDocker
Sobe junto
PostgreSQL
Esc

↑ ↓ navegarEnter abrir191 resultados