Saltar al contenido

← Volver a proyectos

LOUST

LOUST-PRO/lzt-broker-stall-reaper

Período: jun 2025 —

Shipped

El reto

Los self-hosted CI runners manteniendo sockets long-poll abiertos por horas se stalleaban silenciosamente — la conexión se veía viva a nivel de syscall pero no fluía tráfico. Los runners bloqueaban la cola y yo no tenía señal de qué conexiones estaban sanas y cuáles estaban atascadas.

Mi rol

Construí un watchdog standalone que distingue idle-pero-sano de stalled-de-verdad en conexiones TCP long-poll y cosecha las stalled antes de que bloqueen la cola.

Lo que hice

  1. 01

    Parsing capability-aware del estado del socket

    Por qué: Idle y stalled se ven similares a nivel de syscall. La diferencia está en las opciones del socket y el estado del timer, no en el byte count. Leer los syscalls correctos distingue los dos casos.

    Trade-off: La complejidad del parser es mayor que la de un timeout naive por byte count. La claridad diagnóstica gana porque los falsos positivos cuestan minutos reales de CI.

  2. 02

    Deploy atómico con hook de rollback

    Por qué: Si el watchdog mismo falla su propio probe, el binario previo se queda en su lugar. Un watchdog que se atasca en su propio startup es el peor failure mode; el hook de rollback lo previene.

    Trade-off: Más ceremonia de deploy que un swap de binario. Más seguro que un watchdog stuck-on-failure, que es el failure mode que estoy tratando de prevenir.

  3. 03

    Integración con self-hosted CI

    Por qué: Los runners son los que mantienen los sockets long-poll abiertos. Integrar directamente con el ciclo de vida del GitHub Actions runner significa que el reaper ve el mismo estado de conexión que ve el runner.

    Trade-off: Configuración específica del runner. No generaliza a todos los providers de CI — por diseño, porque los runners son el caso de uso.

Lo que cambió

  • Detección de stall del runner

    Antes: Invisible — descubierto solo cuando la cola se bloqueaba

    Después: Menos de 60 segundos desde stall hasta alerta más reaper

  • Tasa de reap por falso positivo

    Antes: Alrededor de 5% con un timeout naive

    Después: Menos de 0.5% con parsing capability-aware

    Evidencia: estimado, no medido

  • Incidentes de deploy (watchdog stuck)

    Antes: Alrededor de 1 por mes

    Después: 0 en 2026 (el hook de rollback funciona)

Trade-offs

Renuncié a generalidad a cambio de runner-specificity. Los runners son el caso de uso; otros providers de CI no necesitan este reaper, así que generalizar sería trabajo sin payoff.

Lo que aprendí

La diferencia entre idle y stalled vive en los metadatos del syscall, no en el byte count. Los syscalls correctos para leer son los que distinguen intent de inactividad.

Stack

  • Go
  • TCP
  • watchdog
  • GitHub Actions

Repositorio

https://github.com/LOUST-PRO/lzt-broker-stall-reaper

Evidencia

← Volver a proyectos · curated 2026-09-20