Una conexión interrumpida puede dejarte sin saber si una solicitud de envío se completó. Un acuse de recibo perdido también puede hacer que un emisor de webhooks entregue un evento que tu aplicación ya almacenó.
Estos fallos ocurren en direcciones opuestas. Bird puede reconocer una solicitud API repetida usando una clave que tú proporcionas. Tu receptor de webhooks necesita su propio registro de eventos que ya aceptó.
¿Cómo reintento un envío de forma segura?
Reutiliza el mismo encabezado Idempotency-Key en cada intento de una operación API lógica.
Tú eliges la clave, de hasta 255 caracteres, y la mantienes entre reintentos. Un valor estable como welcome-user/usr_abc123 puede identificar una operación de mensaje de bienvenida después de que tu proceso se reinicie.
El encabezado se aplica a solicitudes que modifican datos, como POST, PATCH y DELETE. Una solicitud sin clave se procesa sin esta deduplicación. GET ignora el encabezado porque leer el recurso ya es seguro de repetir.
Bird devuelve la respuesta almacenada para una solicitud completada que coincida, incluyendo su estado y cuerpo originales. La respuesta incluye Idempotency-Replay: true, para que puedas identificar esa reutilización en tus registros.
La guía de idempotencia documenta un valor predeterminado de tres horas para la ventana de respuesta completada. Un reintento después de que expire puede ejecutarse como una operación nueva. No dependas de esa clave permanentemente para evitar envíos duplicados.
Los SDK de Bird generan una clave para una mutación y la reutilizan en sus reintentos internos. Bird CLI también genera una clave para una solicitud de mutación cuando no hay una presente. Establece --idempotency-key explícitamente cuando invocaciones de comandos separadas deben compartir la misma operación.
Para el envío de SMTP, usa el encabezado de mensaje X-Bird-Idempotency-Key. Esto permite que un envío reintentado identifique la misma operación.
¿Qué pasa si reutilizo una clave incorrectamente?
Bird rechaza el uso conflictivo de una clave en lugar de devolver una respuesta de una operación diferente.
| Situación | Respuesta y recuperación |
|---|---|
| Misma clave y solicitud después de completarse | La respuesta almacenada, con Idempotency-Replay: true. |
| Clave completada reutilizada para otra solicitud | 409 con E01005, que indica reutilización de clave de idempotencia. Corrige la clave antes de reintentar. |
| Otra solicitud con esa clave aún está en curso | 409 con E01004, que indica solicitud en curso. Espera brevemente y reintenta. |
| La clave excede 255 caracteres | 400 con E01002, que indica entrada no válida. Acorta la clave. |
La comparación incluye el método, el endpoint, los parámetros de ruta, la cadena de consulta y el cuerpo. Para JSON, cambiar los espacios en blanco cambia la identidad de la solicitud, así que preserva el cuerpo original durante los reintentos.
El bloqueo de una operación sin terminar expira en treinta segundos. Ese límite permite que otra solicitud proceda tras una operación abandonada. No establece si un efecto secundario ya ocurrió.
Bird no almacena una respuesta 5xx para reproducirla. Reintenta un error del servidor o un tiempo de espera agotado con la misma clave para que un éxito registrado pueda seguir reutilizándose.
Un rechazo por validación o regla de negocio libera la clave. Puedes corregir esa solicitud rechazada y reintentar con la misma clave porque no se retuvo ninguna respuesta completada.
¿Por qué recibo el mismo webhook dos veces?
Bird puede reintentar un evento que tu receptor ya almacenó si no recibe una respuesta exitosa.
Un receptor puede almacenar un evento justo antes de que su conexión se interrumpa. Bird no ve un acuse de recibo exitoso y reintenta, aunque el receptor ya tiene el evento.
Cada reintento conserva el mismo encabezado webhook-id, que identifica el evento. Una repetición de una entrega fallida también conserva ese identificador, por lo que ambas se pueden reconocer como el mismo evento.
¿Cómo hago que mi handler sea idempotente?
Almacena cada webhook-id bajo una restricción de unicidad en la base de datos antes de programar el trabajo del evento.
Comprobar si ya existe una fila antes de insertar deja una condición de carrera: dos solicitudes concurrentes pueden ver ambas que no hay fila. Deja que la base de datos rechace identificadores duplicados.
Almacena el identificador y el trabajo en la misma transacción. Esto evita que se registre un identificador sin trabajo en cola.
- Verifica la solicitud, luego inserta su identificador y trabajo en la misma transacción.
- Devuelve
2xxdespués de que esa transacción se confirme, para que Bird pueda dejar de reintentar. - Procesa el trabajo almacenado en un worker que pueda repetir sus propias acciones de forma segura.
Si un identificador duplicado ya fue confirmado, devuelve éxito sin crear otro trabajo. Si la transacción falla, devuelve un error para que Bird reintente.
Mantén el trabajo lento fuera del receptor porque esperar a que termine puede hacer que la solicitud agote el tiempo de espera. Un worker puede reintentar por razones ajenas a la entrega de webhooks, así que proteger solo el receptor es insuficiente.
Los eventos también pueden llegar desordenados. Compara las marcas de tiempo de los eventos en timestamp antes de sobrescribir un estado más reciente. Reintentos de webhooks fallidos incluye el ejemplo de costo parcial.
¿En qué no debo confiar?
No asumas que la deduplicación de solicitudes hace imposibles los efectos secundarios duplicados.
Si el almacén de deduplicación de Bird no está disponible, las solicitudes se procesan sin él. Mantén una protección a nivel de negocio donde repetir una acción sería perjudicial.
De igual forma, webhook-id distingue entregas repetidas de un mismo evento. Eventos separados tienen identificadores separados. Tu aplicación sigue decidiendo si esos eventos justifican repetir la misma acción.
Idempotencia documenta el comportamiento de reintentos de API. Webhooks cubre las garantías de entrega independientes que maneja tu receptor.
En resumen
Los reintentos de API y los reintentos de webhook necesitan registros distintos.
Reutiliza Idempotency-Key para una solicitud a Bird. Tu receptor almacena webhook-id para reconocer un evento que ya aceptó.
Las solicitudes rechazadas pueden liberar sus claves.
Los errores de validación y de reglas de negocio no dejan una respuesta completada, lo que permite un reintento corregido con la misma clave.
Una clave completada no puede identificar solicitudes distintas.
Un cuerpo o endpoint de JSON modificado puede producir un conflicto 409. Corrige la clave en lugar de reintentar ese conflicto sin cambios.
La deduplicación tiene límites.
Las solicitudes se procesan si el almacén de deduplicación no está disponible. Mantén las acciones repetidas como algo tolerable también en tu aplicación.