¿Qué es la idempotencia y cómo manejo webhooks duplicados?

La idempotencia hace que una operación repetida tenga el mismo efecto que una sola operación; maneja webhooks duplicados sin repetir su trabajo.

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 Idempotency-Key y una solicitud idéntica en cada reintento. La garantía es la aceptación exactamente una vez: los reintentos coincidentes durante tres horas deben resolverse en una sola operación aceptada, aunque hayas perdido su respuesta.

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ónRespuesta y recuperación
Misma clave y solicitud, respuesta conservadaLa respuesta almacenada mientras se conserva, con Idempotency-Replay: true.
Clave completada reutilizada para otra solicitud409 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 curso409 con E01004, que indica solicitud en curso. Espera brevemente y reintenta.
La clave supera los 255 caracteres422 con E01001 en los endpoints que declaran el encabezado. 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.

Si la solicitud original aún está en curso, espera antes de reintentar. Mantén la misma clave y la misma solicitud para que el reintento identifique la operación original.

API no conserva una respuesta 5xx como respuesta completada. Reintenta un tiempo de espera agotado o un error del servidor con un backoff limitado, la misma clave y una solicitud idéntica durante tres horas. La garantía de aceptación exactamente una vez también cubre una respuesta perdida.

Un rechazo 4xx puede conservarse. Usa una clave nueva para una solicitud corregida: un reintento sin cambios vuelve a devolver el rechazo conservado, y una entrada modificada entra en conflicto con esa clave conservada.

¿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.

  1. Verifica la solicitud, luego inserta su identificador y trabajo en la misma transacción.
  2. Devuelve 2xx después de que esa transacción se confirme, para que Bird pueda dejar de reintentar.
  3. 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.

En una escritura compatible de HTTP, Bird vincula la clave de idempotencia al espacio de trabajo o a la organización de la solicitud. Las operaciones de personal compatibles usan en su lugar la cuenta del miembro del personal que actúa. Si la protección no está disponible, Bird devuelve 503 E01033 IdempotencyUnavailable antes de ejecutar ese intento. Esto no resuelve el resultado de un intento anterior. La garantía de aceptación exactamente una vez cubre los reintentos coincidentes dentro de tres horas. Consulta el estado del mensaje para confirmar la entrega. Si se agotan los reintentos o vence la ventana, comprueba el resultado de la operación original antes de volver a enviarla.

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

  1. 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ó.

  2. Los rechazos también pueden conservarse.

    Un rechazo conservado se vuelve a devolver. Una solicitud corregida necesita una clave nueva porque su entrada es distinta.

  3. 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.

  4. La deduplicación tiene límites.

    La garantía de API cubre la aceptación exactamente una vez de los reintentos coincidentes durante tres horas. Tu receptor de webhooks necesita sus propios registros duraderos de eventos.

Construye sobre la misma red.

Obtén una clave API de prueba de inmediato. El acceso a producción se desbloquea cuando añades un método de pago y verificas un remitente.

Start building with Bird in minutes.