Playbook
Idempotencia (transacción segura repetible) más allá de la solicitud de API (interfaz de programación de aplicaciones) (Idempotencia Transaccion Segura Repetible Mas Alla DE La Solicitud DE API Interfaz DE Programacion DE Aplicaciones)
La idempotencia no es un único encabezado. Es una pila de defensa que debe configurarse por separado en cinco capas diferentes, desde la clave API hasta el puntero de paso.
Motor de pago distribuido
Parte 5 de 22
Una serie de arquitecturas de pago distribuidas que cierran la brecha entre la captura y la finalización.
La idempotencia es una pila, no un encabezado
La mayoría de los equipos aprenden la idempotencia como "agregar un encabezado Idempotency-Key a la solicitud de API" y dejarlo ahí. Esto es sólo la punta del iceberg en los sistemas de pago. El mismo proceso puede "repetirse" a través de su sistema en al menos cinco puntos diferentes: el reintento del cliente, el reintento del webhook de la PSP, la entrega al menos una vez de la cola de mensajes, la recuperación del trabajo del trabajador, la repetición del paso de la saga.```text
Client retry → API idempotency key
PSP retry → Gateway event id
Broker retry → Inbox kaydı
Worker retry → Job uniqueness
Saga retry → Step marker
## Conceptos en la primera mención```text
📦 API Idempotency Key
İstemcinin gönderdiği, aynı isteğin tekrar gönderilmesi halinde aynı sonucu garanti eden benzersiz anahtar.
📦 Gateway Event ID
PSP'nin her webhook veya bildirime verdiği benzersiz kimlik; aynı olayın birden fazla teslimatını ayırt etmeye yarar.
📦 Inbox
Gelen bir olayın işlenmeden önce kaydedildiği, tekrarları filtreleyen dayanıklı bir tablo.
📦 Job Uniqueness
Bir arka plan işinin (job) aynı iş anahtarıyla ikinci kez kuyruğa girmesini önleyen kısıt.
📦 Step Marker
Bir saga adımının tamamlandığını kalıcı olarak işaretleyen, yeniden çalışmayı önleyen kayıt.
```Estos cinco conceptos no son intercambiables. La clave de idempotencia API evita la duplicación entre usted y el cliente; pero no afecta en absoluto el webhook de tu PSP, la entrega de tu cola o el trabajo de tu trabajador.
## Capa 1: solicitud de API
Si el cliente presiona el botón “Pagar” dos veces (retraso de red, doble clic), el cliente envía la solicitud con el mismo `Idempotency-Key`. Si el servidor ha visto esta clave, no volverá a ejecutar el proceso; Devuelve el resultado de la primera ejecución. Esta capa es completamente un contrato entre su API y el cliente.```text
POST /payments Idempotency-Key: abc123
→ ilk çağrı: işlem çalışır, sonuç kaydedilir
→ aynı key ile ikinci çağrı: kayıtlı sonuç döner, işlem tekrar çalışmaz
```## Capa 2: Evento de PSP
La PSP puede enviar el mismo evento (por ejemplo, “captura exitosa”) más de una vez debido a problemas de red o a su propia política de reintento. Cada uno de estos eventos tiene una identificación de evento única proporcionada por PSP. Si ve esta identificación, no debe volver a manejar el evento, pero también debe notificar claramente (ACK) a la PSP que no lo hizo.```text
Webhook #1: event_id=evt_001, type=payment.captured
Webhook #2: event_id=evt_001, type=payment.captured (tekrar teslim)
→ aynı event_id görülmüşse, işlem atlanır, 200 OK döner
```## Capa 3: Cola de mensajes/Bandeja de entrada
Si la verificación de identificación del evento se realiza en el código que procesa el evento directamente, corre el riesgo de que dos trabajadores diferentes procesen el mismo evento en una condición de carrera. Por eso se utiliza el patrón de la bandeja de entrada: el evento se escribe primero en la tabla de la bandeja de entrada con una restricción única; Si esta escritura falla (ya existe), el evento ya se ha visto y la operación se omite de forma segura.```text
INSERT INTO inbox (event_id, ...) VALUES ('evt_001', ...)
→ başarılı: ilk kez görülüyor, işlem kuyruğuna eklenir
→ unique constraint hatası: zaten görülmüş, sessizce atlanır
```## Layer 4: Job itself
Después de la bandeja de entrada, el trabajo se entrega a un trabajo en segundo plano. Este trabajo también puede ponerse en cola más de una vez por sí solo (por ejemplo, durante un mecanismo de reintento o una redistribución). La cola de trabajos debe rechazar un segundo trabajo con la misma clave de trabajo (por ejemplo `payment_id + step_name`).```text
Job key: payment_id=pay_42, step=finalize_stock
→ aynı key ile ikinci job denemesi: kuyruk seviyesinde reddedilir
```## Capa 5: Paso de la saga en sí
Incluso mientras el trabajo se está ejecutando, el paso en sí debe ser idempotente, porque el trabajo en sí puede reiniciarse después de una falla. Esta última capa son marcadores de pasos, que presentamos en el capítulo tres: cada paso marca permanentemente su finalización, y si el paso se ejecuta nuevamente, verifica esa marca para no hacer el trabajo real (deducir inventario, abrir un registro financiero) nuevamente.```text
Step marker: finalize_stock=DONE (payment_id=pay_42)
→ adım tekrar çağrılırsa, marker kontrol edilir, iş tekrar yapılmaz
```## ¿Por qué se requieren estas cinco capas por separado?
Cada capa responde a una pregunta diferente sobre "quién reenvía": el cliente, el PSP, la cola, el trabajador o el trabajo en sí. Si solo instala idempotencia en la capa API y omite las otras cuatro, es posible que su sistema tenga una saga de finalización ejecutándose "una vez en la API, pero tres veces en segundo plano", y solo notará este error en producción, generalmente con una queja de un cliente.
## Los enfrentamientos más confusos de este episodio.```text
❌ Idempotency-Key header'ı eklemek, idempotency problemini çözer
✓ Bu header sadece istemci-API katmanındaki tekrarı çözer
❌ PSP event id kontrolü tek başına yeterlidir
✓ Event id kontrolü, race condition'a karşı bir inbox/unique constraint ile desteklenmelidir
❌ Job kuyruğu at-least-once teslimat yaparsa, iş otomatik olarak idempotent olur
✓ At-least-once teslimat + idempotent olmayan iş = güvenli değil; iş kendi başına idempotent olmalıdır
❌ Bir saga adımı başarıyla tamamlandıysa tekrar çağrılması zararsızdır
✓ Adım işaretçisi yoksa tekrar çağrı, yan etkiyi (stok düşme, ödeme) ikinci kez tetikler
Haga una lista de verificación de su pila de idempotencia
- ¿Su API tiene una clave de idempotencia? Si es así, ¿cuánto tiempo se conserva el resultado?
- ¿Verifica los identificadores de eventos en los webhooks de su PSP o procesa cada webhook directamente?
- ¿Tiene una restricción única para la identificación del evento en su tabla de Bandeja de entrada o realiza la verificación en el código de la aplicación (riesgo de condición de carrera)?
- ¿Su cola de trabajos rechaza un segundo trabajo con la misma clave de trabajo?
- ¿Cada paso de la saga busca un marcador que verifique su propia finalización o rehace el trabajo cada vez que se ejecuta?
Si faltan dos de estas cinco capas, es probable que su sistema sea propenso a errores de doble confirmación "raros pero recurrentes".
Cosas para recordar de esta sección
- La idempotencia no es un único encabezado ni un único control; Es una pila que debe instalarse por separado en al menos cinco capas independientes.
- Cada capa responde a una fuente de reproducción diferente (cliente, PSP, cola, trabajador, paso de saga); uno no incluye al otro.
- El patrón de la bandeja de entrada es una solución estructural que hace que la verificación de identificación del evento sea segura contra las condiciones de carrera, no es solo una verificación "si".
- En el modelo de entrega al menos una vez, un paso de trabajo no idempotente tarde o temprano se ejecutará dos veces.
Reducir la Idempotencia a un encabezado es como poner una sola puerta en un edificio de cinco pisos y dejar abiertas las ventanas de los otros cuatro pisos.
FAQ
Frequently asked questions
¿Qué es la clave de idempotencia API?
Una clave única enviada por el cliente que garantiza el mismo resultado si se vuelve a enviar la misma solicitud.
¿Qué es el ID de evento de puerta de enlace?
El ID único que el PSP proporciona a cada webhook o notificación; Sirve para distinguir múltiples entregas de un mismo evento.
¿Es cierto que "Agregar el encabezado Idempotency-Key resuelve el problema de idempotencia"?
Este encabezado solo resuelve la repetición en la capa API del cliente.
¿Qué soluciona esta sección?
Esta sección le indica cómo configurar la idempotencia en cada una de estas cinco capas por separado, en lugar de en un solo punto. La idempotencia no es un único encabezado ni un único control; Es una pila que debe instalarse por separado en al menos cinco capas independientes. La mayoría de los equipos aprenden la idempotencia como "agregar un encabezado `Idempotency-Key` a la solicitud de API" y dejarlo ahí. Esto es sólo la punta del iceberg en los sistemas de pago. El mismo proceso puede "repetirse" a través de su sistema en al menos cinco puntos diferentes: el reintento del cliente, el reintento del webhook de la PSP, la entrega al menos una vez de la cola de mensajes, la recuperación del trabajo del trabajador, la repetición del paso de la saga.
Principios de ingeniería aprendidos
- La idempotencia no es un encabezado único; Es una pila que debe configurarse por separado en las capas de API, puerta de enlace, bandeja de entrada, trabajo y pasos de saga.
- Cada capa responde a una fuente diferente de repetición; Instalar uno y omitir los demás deja el sistema semiprotegido.
- En el modelo de entrega al menos una vez, un paso no idempotente seguramente se ejecutará dos veces, tarde o temprano.
Continuar leyendo
Continuar leyendo
Siguiente en la serie
Fiabilidad del webhook en sistemas de pago
Los webhooks se repiten, desaparecen, llegan desordenados y con retraso. Verifique la firma, proporcione ACK rápido, nunca ejecute trabajos pesados…
Siguiente en la serie
Diseño de instantáneas de pago inmutable: la decisión que congela el carrito
Leer el carrito en vivo cuando comienza el pago deja indeciso el monto y la moneda. La finalización no funcionará de manera confiable sin una instantánea…
Misma serie
Patrón de bandeja de salida/bandeja de entrada en sistemas de pago
Si escribir en la base de datos y publicar un evento no están en la misma transacción, uno de ellos se perderá o se repetirá.…