GH GambleHub

Idempotencia y llaves

¿Qué es la idempotencia?

Idempotencia: propiedad de operación en la que una repetición con el mismo identificador no cambia el efecto final. En sistemas distribuidos, esta es la forma principal de hacer que el resultado sea equivalente a «exactamente un procesamiento», a pesar de retraídas, mensajes duplicados y timeouts.

Idea clave: cada operación potencialmente repetible debe ser marcada con una clave por la cual el sistema reconoce «ya lo ha hecho» y aplica el resultado no más de una vez.

Donde

Pagos y balances: cargos/abonos por 'operation _ id'.
Reservas/cuotas/límites: la misma ranura/recurso.
Webhooks/notificaciones: la entrega repetida no debe duplicar el efecto.
Importar/migrar: volver a ejecutar archivos/paquetes.
Procesamiento de streaming: tomas del bróker/CDC.

Vistas de claves y ámbito

1. Llave de operación: identificador de intento específico de la operación empresarial

Ejemplos: 'idempotency _ key' (HTTP), 'operation _ id' (RPC).
Área: servicio/unidad; se almacena en una tabla de deduplicación.

2. Clave de evento: identificador único de evento/mensaje

Ejemplos: 'event _ id' (UUID), '(producer_id, sequence)'.
Ámbito: consumidor/grupo de consumidores; protege las proyecciones.

3. Business key es la clave natural de la materia

Ejemplos: 'payment _ id', 'invoice _ number', '(user_id, día)'.
Ámbito: agregado; se aplica en verificaciones de unicidad/versión.

💡 A menudo se utilizan juntos: 'operation _ id' protege el comando, 'event _ id' - entrega, 'business key' - invariantes del agregado.

Política de retención y TTL

Llaves TTL ≥ posible ventana de repetición: retén de registro + retardo de red/proceso.
Para dominios críticos (pagos) TTL: días/semanas; para telemetría - reloj.
Limpie las tablas de dedoop de fondo con jobs; para auditoría: archive.

Almacenes para claves (deduplicación)

Transaccional DB (recomendado): índices confiables de upsert/unique, transacción conjunta con efecto.
KV/Redis: rápido, conveniente para un TTL corto, pero sin una transacción conjunta con OLTP - cuidado.
State store stream procesador: local + chenjlog en el corredor; bien en Flink/KStreams.

Esquema (opción en el DB):
  • idempotency_keys

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

Índices: '(consumer_id, op_id)' - único.

Técnicas básicas de implementación

1) Transacción «efecto + progreso»

Escribir el resultado y confirmar el progreso de la lectura/posición - en una sola transacción.

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 (versión de la unidad)

Protege contra el doble efecto durante las carreras:
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)

Operación «acumular una vez»:
sql insert into bonuses(user_id, op_id, amount)
values(:u,:op,:amt)
on conflict (user_id, op_id) do nothing;

Idempotencia en los protocolos

HTTP/REST

Título 'Idempotency-Key: <uuid' hash> '.
El servidor almacena el registro de claves y vuelve a devolver la misma respuesta (o código '409 '/' 422' en un conflicto de invariantes).
Para los «inseguros» POST - obligatorio 'Idempotency-Key' + timaut sostenible/política retray.

gRPC/RPC

Los metadatos 'idempotency _ key', 'request _ id' + deadline.
Implementación del servidor - como en NAT: tabla de dedup en una transacción.

Corredores/streaming (Kafka/NATS/Pulsar)

Productor: estable 'event _ id '/productor idempotente (donde se mantiene).
Consumer: dedoop por '(consumer_id, event_id)' y/o por la versión de negocio de la unidad.
DLQ separado para mensajes no idempotentes/dañados.

Webhooks y socios externos

Requiera 'Idempotency-Key '/' event _ id' en el contrato; La entrega repetida debe ser segura.
Almacene 'notification _ id' y los estados de envío; Con Retray - No duplique.

Diseño de claves

Determinismo: los retraídos deben enviar la misma clave (generar por adelantado en el cliente/orquestador).
Ámbito de visibilidad: forme 'op _ id' como 'service: aggregate: id: purpose'.
Colisiones: utilice UUIDv7/ULID o hash de los parámetros de negocio (con sal si es necesario).
Jerarquía: el 'operation _ id' general en el frente → se transmite a todas las suboperaciones (cadena idempotente).

Aspectos de productos y UX

Una solicitud de clave repetida debe devolver el mismo resultado (incluido el cuerpo/estado) o una «ya ejecutada» explícita.
Muestre al usuario los estados de «operación procesada/completada» en lugar de volver a intentarlo «a suerte».
Para operaciones largas, polling por clave ('GET/operations/{ op _ id}').

Observabilidad

Lógica 'op _ id', 'event _ id', 'trace _ id', resultado: 'APPLIED '/' ALEADY _ APPLIED'.
Métricas: porcentaje de repeticiones, tamaño de las tablas de dedoop, tiempo de transacción, conflictos de versiones, tasa DLQ.
Trais: la clave debe pasar por el comando → evento → proyección → llamada externa.

Seguridad y cumplimiento

No almacene la PII en claves; clave - ID, no payload.
Cifre los campos sensibles en las entradas de Dedup con TTL de larga duración.
Política de retención: TTL y archivos; el derecho al olvido - a través de la encriptación de respuestas/metadatos (si contienen PII).

Pruebas

1. Duplicados: ejecución de un solo mensaje/consulta 2-5 veces - efecto exactamente uno.
2. Caída entre pasos: antes/después de registrar el efecto, antes/después de fijar el offset.
3. Restart/reequilibrio de los consumidores: no hay doble uso.
4. Competencia: consultas paralelas con un 'op _ id' → un efecto, la segunda es 'ALEADY _ APPLIED/409'.
5. Claves de larga vida: comprueba la caducidad de la TTL y las repeticiones después de la recuperación.

antipatterny

Una nueva clave aleatoria para cada retiro: el sistema no reconoce repeticiones.
Dos commitas separadas: primero el efecto, luego el offset - la caída entre ellos duplica el efecto.
Confianza sólo para el corredor: no hay dedoop en el azul/unidad.
No hay versión del agregado: el evento de repetición cambia el estado por segunda vez.
Fat keys: la clave incluye campos de negocio/PII → fugas e índices complejos.
No hay respuestas repetibles: el cliente no puede retractarse con seguridad.

Ejemplos

POST de pago

Cliente: 'POST/payments' + 'Idempotency-Key: k-789'.
Servidor: transacción: crea un 'pago' y una entrada en 'idempotency _ keys'.
Repetición: devuelve el mismo '201 '/cuerpo; en conflicto invariante - '409'.

Acumulación de bonificación (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;

Proyección de eventos

Consumer almacena 'seen (event_id)' y 'version' de la unidad; repetición - upsert ignorado/idempotente.
El progreso de la lectura se registra en la misma transacción que la actualización de proyección.

Lista de comprobación de producción

  • Se ha definido una clave idempotente y su área de visibilidad para todas las operaciones inseguras.
  • Hay tablas de dedoop con TTL e índices únicos.
  • El efecto y el progreso de la lectura se combinan atomicamente.
  • El modelo escrito incluye una competencia optimista (versión/sequence).
  • Los contratos API registran 'Idempotency-Key '/' operation _ id' y el comportamiento de las repeticiones.
  • Métricas y registros contienen 'op _ id '/' event _ id '/' trace _ id'.
  • Pruebas de duplicados, caídas y carreras - en CI.
  • Se han respetado las políticas de TTL/archivo y seguridad PII.

FAQ

¿En qué se diferencia 'Idempotency-Key' de 'Request-Id'?
'Request-Id' - rastreo; «Idempotency-Key» es el identificador semántico de la operación, obligatorio para las repeticiones.

¿Se puede hacer idempotencia sin DB?
Para una ventana corta, sí (caché Redis/intraprocesado), pero sin una transacción conjunta, el riesgo de tomas aumenta. En dominios críticos, mejor en una sola transacción de BD.

¿Qué hacer con los socios externos?
Negocie las claves y las respuestas repetibles. Si el socio no es compatible, envuelva la llamada en su capa idempotente y almacene el «ya aplicado».

¿Cómo elegir TTL?
Resume los retardos máximos: retén de registro + caso de trabajo de red/rebalance + búfer. Agregue el inventario (× 2).

Resultado

La idempotencia es la disciplina de claves, transacciones y versiones. Los identificadores de operación constantes + la fijación atómica del efecto y el progreso de lectura + sinks/proyecciones idempotentes producen «exactamente un efecto» sin la magia del nivel de transporte. Haga que las claves sean deterministas, que el TTL sea realista y que las pruebas sean malintencionadas. Entonces los retraídos y duplicados se convertirán en una rutina, no en incidentes.

Contact

Póngase en contacto

Escríbanos ante cualquier duda o necesidad de soporte.¡Siempre estamos listos para ayudarle!

Iniciar integración

El Email es obligatorio. Telegram o WhatsApp — opcionales.

Su nombre opcional
Email opcional
Asunto opcional
Mensaje opcional
Telegram opcional
@
Si indica Telegram, también le responderemos allí además del Email.
WhatsApp opcional
Formato: +código de país y número (por ejemplo, +34XXXXXXXXX).

Al hacer clic en el botón, usted acepta el tratamiento de sus datos.