GH GambleHub

Idempotidade e chaves

O que é idempotação

Idempotidade é uma propriedade de operação em que uma repetição com o mesmo ID não altera o efeito final. Nos sistemas distribuídos, esta é a principal forma de tornar o resultado equivalente a «exatamente um processamento», apesar de retratos, mensagens duplicadas e temporizações.

A ideia-chave é que cada operação potencialmente repetida deve ser marcada por uma chave em que o sistema reconheça «isso já foi feito» e aplica o resultado no máximo uma vez.

Onde isso é importante

Pagamentos e balanços: débitos/inscrições por 'operation _ id'.
Reservas/quotas/limites: mesmo slot/recurso.
Webhooks/notificações: Uma nova entrega não deve duplicar o efeito.
Importação/migração: reaproveitamento de arquivos/pacotes.
Processamento de strim: duplas de corretor/CDC.

Tipos de chaves e seu alcance

1. Operation key - ID de uma tentativa específica de transação

Os exemplos são 'idempotency _ key' (HTTP), 'operation _ id' (RPC).
Área: serviço/unidade; armazenado na tabela de dedução.

2. Event key - Identificador único de evento/mensagem

Exemplos: 'event _ id' (UUID), '(producer _ id, sequence)'.
Área: consumidor/grupo de consumidores; protege projeções.

3. Business Key - a chave natural da área de objetos

Exemplos de 'payment _ id', 'invoice _ number', '(user _ id, day)'.
Área: unidade; é aplicado em verificações de exclusividade/versão.

💡 Usados frequentemente juntos: 'operation _ id' protege o comando; 'event _ id', 'business key', invariantes do aparelho.

TTL e política de armazenamento

A TTL de chaves ≥ uma possível janela de repetição: retenção de logs + atrasos de rede/processo.
Para domínios críticos (pagamentos) TTL - dias/semanas; para a telemetria, um relógio.
Limpe as tabelas de background jobs; para auditoria - arquive.

Armazenamento de chaves (dedução)

BD transacional (recomendado): índice upsert/unique confiável, transação conjunta com efeito.
KV/Redis: rápido, conveniente para um TTL curto, mas sem transação conjunta com OLTP - cuidado.
State store processador estrim: local + chainjog no corretor; bem em Flink/KStreams.

Esquema (opção no banco de dados):
  • idempotency_keys

`consumer_id` (или `service`), `op_id` (PK на пару), `applied_at`, `ttl_expires_at`, `result_hash`/`response_status` (опц.) .

Índice: '(consumer _ id, op _ id)' é único.

Técnicas de implementação básicas

1) Transação «efeito + progresso»

Gravar o resultado e fixar o progresso da leitura/posição - em uma transação.

pseudo begin tx if not exists(select 1 from idempotency_keys where consumer=:c and op_id=:id) then
-- apply effect atomically (upsert/merge/increment)
apply_effect(...)
insert into idempotency_keys(consumer, op_id, applied_at)
values(:c,:id, now)
end if
-- record reading progress (offset/position)
upsert offsets set pos=:pos where consumer=:c commit

2) Optimistic Concurrency (versão do aparelho)

Protege contra o efeito duplo nas corridas:
sql update account set balance = balance +:delta,
version = version + 1 where id=:account_id and version=:expected_version;
-- if 0 rows are updated → retry/conflict

3) Sinks Idempotentes (upsert/merge)

Operação «faturar uma vez»:
sql insert into bonuses(user_id, op_id, amount)
values(:u,:op,:amt)
on conflict (user_id, op_id) do nothing;

Idempotidade nos protocolos

HTTP/REST

Título 'Idempotency-Key: <uuid' hash> '.
O servidor armazena a gravação da chave e devolve novamente a mesma resposta (ou o código '409 '/' 422' no conflito de invariantes).
Para os «inseguros» POST - obrigatório 'Idempotency-Key' + timeout/política de retração sustentável.

gRPC/RPC

Metadados 'idempotency _ key', 'request _ id' + deadline.
Implementação de servidor - como no REST: tabela de dedução na transação.

Corretores/streaming (Kafka/NATS/Pulsar)

Produtor: estável 'event _ id '/idumpotente (onde suportado).
Consumer: deadup por '(consumer _ id, event _ id)' e/ou pela versão empresarial do aparelho.
DLQ separado para mensagens não identificadas/danificadas.

Webhooks e parceiros externos

Exija 'Idempotency-Key '/' event _ id' no contrato; Uma nova entrega deve ser segura.
Guarde 'notification _ id' e os estados de envio; na retração - não duplique.

Projeto de chaves

Determinação: Retrações devem enviar a mesma chave (gere antecipação no cliente/orquestrador).
Área de visibilidade: Forma 'op _ id' como 'service: aggregate: id: purpose'.
Conflitantes: use UUIDv7/ULID ou hash de parâmetros de negócios (com sal, se necessário).
Hierarquia: geral 'operation _ id' na frente → é transmitido para todas as posições (cadeia idumpotente).

UX e aspectos de alimentos

Uma nova solicitação de chave deve retornar o mesmo resultado (incluindo corpo/status) ou um «já concluído» explícito.
Mostre ao usuário os estados de «operação processada/concluída» em vez de tentar novamente «sorte».
Para operações de longa duração, a chave é polling ('GET/operações/se por causa de').

Observabilidade

Logue 'op _ id', 'event _ id', 'trace _ id', o desfecho é 'APPLIED '/' ALREADY _ APPLIED'.
Métricas: proporção de repetições, tamanho de tabelas de dedução, tempo de transações, conflitos de versões, taxa de DLQ.
A chave deve passar pelo comando → evento → projeção → chamada externa.

Segurança e Complacência

Não guarde PII nas chaves; chave - ID, não payload.
Criptografe os campos sensíveis nos registros de dedução com TTL de longa duração.
Política de armazenamento: TTL e arquivos; direito ao esquecimento - através de cripto-apagar respostas/metadados (se eles contêm PII).

Testes

1. Duplicado: uma mensagem/solicitação de 2 a 5 vezes - o efeito é exatamente uma.
2. Queda entre os passos: antes/depois da gravação do efeito, antes/depois da fixação do ofset.
3. Restart/rewalance dos consumidores: não há dupla aplicação.
4. Concorrência: solicitações paralelas com um 'op _ id' → um efeito, o outro é 'ALREADY _ APPLIED/409'.
5. Chaves de longa duração: Verificação do vencimento da TTL e repetições após a recuperação.

Antipattern

Nova chave aleatória para cada retrai, o sistema não reconhece as repetições.
Dois grupos individuais, primeiro o efeito, depois o efeito ofset - a queda entre eles duplica o efeito.
A confiança é apenas para o corretor, a falta de dedução em sinca/unidade.
Não há uma versão do aparelho: um novo evento muda de estado pela segunda vez.
Fat keys: a chave inclui campos de negócios/PII → vazamentos e índices complexos.
Sem respostas repetitivas, o cliente não pode retocar de forma segura.

Exemplos

Post de pagamento

Cliente: 'POST/payments' + 'Idempotency-Key: k-789'.
Servidor: transação - Cria 'payment' e uma gravação em 'idempotency _ keys'.
Repetição: devolve o mesmo '201 '/corpo; no conflito do invariante, '409'.

Pagamento de bónus (sink)

sql insert into credits(user_id, op_id, amount, created_at)
values(:u,:op,:amt, now)
on conflict (user_id, op_id) do nothing;

Projeção a partir de eventos

O Consumer armazena 'seen' (event _ id) 'e' version 'do aparelho; repetição - upsert ignorado/idimpotente.
O progresso da leitura é registrado na mesma transação que a atualização da projeção.

Folha de cheque da produção

  • Todas as operações não seguras definiram a chave Idumpotent e sua área de visibilidade.
  • Há tabelas de dedução com TTL e índices exclusivos.
  • O efeito e o progresso da leitura são atômicos.
  • O modelo write inclui uma competição otimista (versão/sequence).
  • Os contratos de API registram 'Idempotency-Key '/' operation _ id' e comportamento de repetição.
  • As métricas e os logs contêm 'op _ id '/' event _ id '/' trace _ id'.
  • Testes de duplicação, queda e corrida - em CI.
  • A política TTL/arquivo e a segurança do PII foram cumpridas.

FAQ

Em que 'Idempotency-Key' é diferente de 'Request-Id'?
'Request-Id' - rastreamento; «Idempotency-Key» é o ID semântico da operação, obrigatório igual quando repetido.

É possível fazer idempotidade sem base de dados?
Para uma janela curta, sim (Redis/kesh intraprocessado), mas sem transação compartilhada, o risco de duplicação aumenta. Em domínios críticos, melhor em transações de base de dados.

O que fazer com os parceiros externos?
Negocie as chaves e as respostas repetidas. Se o parceiro não suporta, inverte a chamada para sua camada idumpotente e guarde «já aplicado».

Como escolher a TTL?
Some os atrasos máximos de retenção do logs + worst-case rede/rebalance + tampão. Adicione o estoque (x 2).

Resultado

Idempotidade é uma disciplina de chaves, transações e versões. Identificadores de operações robustos + atômico fixação do efeito e progresso da leitura + sinks/projeções idumpotentes produzem «exatamente um efeito» sem a magia do nível de transporte. Tornem as chaves determinadas, as TTL realistas e os testes maliciosos. Então os retais e duplicados serão uma rotina, não incidentes.

Contact

Entrar em contacto

Contacte-nos para qualquer questão ou necessidade de apoio.Estamos sempre prontos para ajudar!

Iniciar integração

O Email é obrigatório. Telegram ou WhatsApp — opcionais.

O seu nome opcional
Email opcional
Assunto opcional
Mensagem opcional
Telegram opcional
@
Se indicar Telegram — responderemos também por lá.
WhatsApp opcional
Formato: +indicativo e número (ex.: +351XXXXXXXXX).

Ao clicar, concorda com o tratamento dos seus dados.