Repository navigation
feat: [TESIS-147] show and operate the failed events queue - #63
Conversation
The retry engine (RF-16) records every failed webhook and outbound request, retries it with exponential backoff and exposes list, retry and discard endpoints, but nothing showed it: the operator could not tell a sale failed to come in, and the resilience acceptance criterion could not be shown. The new Eventos fallidos section lists the queue with tabs per status and their counts, names each event type in words, and shows the attempts, the next automatic retry and the last error with its HTTP status. Each row offers only the actions the API accepts for its status; discarding asks first, and a 422 on retry is explained because the event changed status meanwhile. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Revisado. Lo veo bien para implementar. Mismo caso que #62 y por el mismo motivo: RF-16 (motor de reintentos / DLQ) está completo en la API y no se veía en ningún lado. Verifiqué que en Lo que verifiqué
Para la demo Esta pantalla sin eventos no muestra nada. Si va a usarse para defender el criterio de resiliencia, o se provoca un fallo a mano antes (un webhook con un producto sin mapear alcanza) o entra proyecto-api#111, que siembra actividad. Lo digo para que no se descubra el día de la presentación. |
TomasMartin2004
left a comment
There was a problem hiding this comment.
Revisión del diff completo. El código es idéntico al que leí cuando los PRs estaban en draft —ningún commit nuevo—, así que lo que sigue es el veredicto formal.
✅ Aprobado
Mismo caso que #62 y por el mismo motivo: RF-16 (motor de reintentos / DLQ) está completo en la API y no se veía en ningún lado. Verifiqué que en master no hay carpeta features/failed-events. El operador no se entera de que una venta no entró, y en la defensa no hay forma de mostrar el criterio de aceptación de resiliencia de E4b, que es uno de los diferenciadores que el proyecto vende.
Lo que verifiqué
utils/actions.tses el núcleo y está bien resuelto: el mapaACTIONScoincide exactamente conWebhooks::RequeueFailedEvent::REQUEUEABLE_STATUSES(pending,dead,discarded), que fui a chequear contra el código del backend. Ofrecer un botón que la API va a rechazar con 422 es prometer algo que no pasa, y acá no pasa.- Que
processingofrezca sólo descarte está bien pensado: la API acepta el reintento sólo si venció el claim del worker, y eso el front no lo puede saber. La alternativa —mostrar el botón y cruzar los dedos— sería peor. - Misma estructura de feature que el resto,
architecture.mdyroutes.test.tsxactualizados. - La regla vive en una función pura con sus tests, no embebida en el JSX de la fila.
🟡 Para la demo
Esta pantalla sin eventos no muestra nada. Si va a usarse para defender el criterio de resiliencia, o se provoca un fallo a mano antes —un webhook con un producto sin mapear alcanza— o entra proyecto-api#111, que siembra actividad. Lo digo para que no se descubra el día de la presentación.
…-events-queue Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ticket de Jira
https://proyectofinalfrlp.atlassian.net/browse/TESIS-147
Descripción
El motor de reintentos (RF-16, Módulo E del alcance) está completo en la API: cada webhook entrante o pedido saliente que falla queda en
failed_events, se reintenta con backoff exponencial y hay endpoints para listar, reintentar y descartar. Pero no se veía en ningún lado: el operador no se enteraba de que una venta no entró, y en la demo no había forma de mostrar el criterio de aceptación «los webhooks fallidos son recuperados automáticamente sin pérdida de datos» (E4b §2.6). Este PR agrega la sección Eventos fallidos (/failed-events).Decisiones que conviene mirar:
Sin maqueta. Es la
DataTabledel DS con pestañas por estado, como el catálogo: Todos, Pendientes, Agotados, Resueltos y Descartados, con su contador (una consulta de una fila por pestaña, que leemeta.total).processingno tiene pestaña: dura segundos mientras un worker lo intenta, y aparece en «Todos». Las filas agotadas se resaltan.Sólo las acciones que la API acepta.
utils/actions.tses el espejo deRequeueFailedEvent::REQUEUEABLE_STATUSES: reintentar enpending,deadydiscarded; descartar en todo lo no resuelto ni descartado. Van como botones en una columna y no en el menú de laDataTable, que no admite opciones por fila.processingno ofrece reintento: la API lo acepta sólo si el claim del worker venció, y eso el front no lo puede ver (si quedó colgado, el barrido lo rescata solo).El tipo de evento, en palabras.
webhooks.order_ingestion→ «Venta recibida de un canal», etc. Un tipo desconocido se muestra tal cual: mejor un nombre técnico que esconder que existe.Un solo «ahora» por lectura. «Próximo reintento» y «Registrado» se calculan contra el
dataUpdatedAtde la query, no contra la hora de cada render: si no, un re-render cualquiera movería los «dentro de 4 minutos» sin que la tabla haya cambiado.Sin
payload. La API no lo expone a propósito (puede traer datos del cliente). Para diagnosticar quedan el último error y el status HTTP.features/failed-eventsconapi.ts,types.ts,queryKeys.ts,hooks/useFailedEvents.ts,content.tsyutils/actions.ts.FailedEventsPage: tabla paginada por el backend, pestañas con contadores, reintento y descarte con confirmación./failed-eventscon su entrada «Eventos fallidos» en el Sidebar y actualizaroutes.test.tsx.docs/guidelines/architecture.md.Evidencia visual
Pendiente de captura con la API levantada. El comportamiento está cubierto por los tests de la página y de las reglas de acciones.
Cómo probar
Precondición: API de
master,bin/rails db:seed, login con un usuario de Norte,bin/jobscorriendo.POST /api/v1/webhooks/integrations/<token>con un payload de orden cuyo producto no está vinculado (o apagar la red del courier en desarrollo).1 / 5intentos, el próximo reintento y el último error.max_attemptsdesde la consola) → pasa a «Agotado», resaltado, y cuenta en la pestaña.0 / 5.Verificación:
npm run test(690 tests, 0 fallas),npm run lint,npm run format:checkynpm run buildlimpios.Impacto y consideraciones
¿Introduce breaking changes?
No
¿Requiere nuevas variables de entorno?
No
¿Afecta la arquitectura o genera un nuevo patrón?
No. Una feature nueva con la estructura estándar.
Conflicto esperable: proyecto-web#62 (depósitos) también agrega una entrada al Sidebar en
routes.tsxy su test. Es un conflicto de líneas vecinas, se resuelve dejando las dos.🤖 Generated with Claude Code