Skip to main content

Estados de una entrega

Cada entrega es una fila en webhook_dispatch. Su status evoluciona así: attempts, last_http_status y last_error se actualizan en cada intento, de modo que el libro mayor se explica solo. attempts es el recuento de POST de toda la vida de esa fila: un replay del operador no lo pone a cero.

Matriz de resultados

Solo los resultados terminales y exhausted incrementan consecutive_failures. Un 503 que se recupera en el siguiente reintento no es una entrega perdida y no mueve el cortacircuitos.

Calendario de backoff

Los fallos reintentables se reenvían con un calendario fijo, visible para el suscriptor (WEBHOOK_OUT_MAX_ATTEMPTS = 5): next_retry_at en la fila del libro mayor muestra la hora exacta del próximo intento. El campo attempt del cuerpo se incrementa mientras id permanece igual.

Desactivación automática

Un endpoint muerto no debe consumir capacidad de cola indefinidamente. Cuando un webhook acumula 20 entregas consecutivas terminales o exhausted:
  • is_actived pasa a false,
  • se estampa disabled_at y disabled_reason = "consecutive-failures",
  • la etapa route deja de escribir filas de dispatch para él,
  • el componente de salud webhook-out y el resumen del dashboard lo cuentan en disabled_auto.
Las entregas ya en vuelo terminan su intento actual; no se programa nada nuevo.

Reactivar

  1. Arregla el endpoint (o su URL mediante PATCH).
  2. Envía una entrega de prueba: POST /api/v3/webhook/webhook/{id}/test.
  3. Activa: PATCH /api/v3/webhook/webhook/{id}/active con { "is_actived": true }. Esto limpia consecutive_failures, disabled_at y disabled_reason.
  4. Reenvía lo que se perdió (abajo).
Existe otro disabled_reason: legacy-secret-rotation-required. Los webhooks anteriores a este release fueron desactivados por la migración 0237 porque sus secretos son previos al contrato de firma; rota el secreto y después activa.

Replay

POST /api/v3/webhook/dispatch/{id}/replay reencola una fila del libro mayor (status = pending, último error y next_retry_at limpiados) sin reiniciar attempts. El siguiente POST incrementa el mismo contador, así que la fila conserva el historial completo de entregas. El suscriptor recibe el mismo id, event y data; attempt es el siguiente número secuencial.
  • Reenviar una fila error o exhausted no necesita cuerpo.
  • Reenviar una fila success devuelve 409 Conflict salvo que el cuerpo incluya { "confirm_duplicate": true }, porque el suscriptor verá el evento dos veces. Los endpoints que deduplican por id lo gestionan de forma transparente.
Los reintentos automáticos siguen deteniéndose a los cinco POST (WEBHOOK_OUT_MAX_ATTEMPTS). Un replay del operador sobre una fila exhausted hace un POST adicional; si ese POST es reintentable, la fila vuelve a exhausted (sin nueva programación automática). Horizon Enterprise expone la misma acción por fila en la pantalla de detalle del webhook, con filtros por estado, evento y fecha.
El replay no resucita el recurso origen. Si la fila fue purgada desde entonces, data.document_id sigue apuntando al id antiguo y tu lectura por la API devolverá 404 — trátalo como “ya no existe”.