System Design/02 - Componentes2 min
Idempotent Operations
- Que problema isso resolve?
- Quando usar / quando NÃO usar?
- Qual o principal trade-off?
- Como isso falha em produção?
Conceito
Uma operação é idempotente quando executá-la várias vezes produz o mesmo resultado que executá-la uma vez.
Isso importa porque, em rede, você nunca sabe se a requisição falhou ou se só a resposta se perdeu. O cliente que não recebe resposta tem duas opções: repetir (e arriscar duplicar) ou não repetir (e arriscar perder). Idempotência elimina o dilema.
Nos métodos HTTP
| Método | Idempotente? | Seguro? |
|---|---|---|
GET, HEAD |
Sim | Sim (não altera) |
PUT |
Sim — define o estado final | Não |
DELETE |
Sim — apagar de novo é no-op | Não |
POST |
Não | Não |
PATCH |
Depende (x = 5 sim; x += 1 não) |
Não |
Como tornar uma operação idempotente
| Técnica | Como funciona |
|---|---|
| Chave de idempotência | Cliente envia um UUID; o servidor guarda o resultado e devolve o mesmo em repetição |
| Chave natural | Usar um ID de negócio como chave primária — a segunda escrita colide, não duplica |
| Escrita condicional | INSERT ... ON CONFLICT DO NOTHING, compare-and-swap, ETag/If-Match |
| Formulação absoluta | SET saldo = 100 em vez de saldo = saldo - 50 |
| Tabela de deduplicação | Registrar IDs já processados, com TTL |
Trade-offs
Idempotência custa estado: alguém precisa lembrar o que já foi processado. Essa tabela cresce, precisa de TTL, e vira mais um componente com sua própria disponibilidade.
Há também uma janela de corrida: duas requisições com a mesma chave chegando simultaneamente exigem que a checagem e a gravação sejam atômicas — senão as duas passam. Um INSERT com constraint única resolve; um SELECT seguido de INSERT não.
A alternativa — entrega exactly-once no transporte — é mais cara e mais frágil. O consenso da indústria é at-least-once no transporte + idempotência no consumidor.
Exemplo prático
Um pagamento: o cliente envia POST /cobranca com header Idempotency-Key: 7f3a.... A rede cai antes da resposta chegar. O cliente repete com a mesma chave.
O servidor encontra a chave já registrada e devolve a resposta original, sem cobrar de novo. Sem a chave, a segunda tentativa criaria uma segunda cobrança — e o cliente seria debitado duas vezes por um problema de rede.
O mesmo padrão vale para consumidor de fila: como Message Queues entregam pelo menos uma vez, o worker precisa registrar o ID processado antes de considerar o trabalho concluído.
Relacionado
Parte de 02 - MOC Componentes · roadmap.sh/system-design