BookinglyTech News
Infraestructura

Un circuit breaker de cuota no basta: cómo decidir qué trabajos relanzar en launchd

El autor de claude-quota-guard.py publica quota-catchup.py, la segunda mitad del problema: qué hacer con los trabajos que el circuito se saltó en launchd.

2 min de lecturaDev.to0 vistas

Un circuit breaker que corta todos los trabajos en cuanto se agota la cuota resuelve la mitad del problema. La otra mitad aparece después: cuando el circuito vuelve a cerrarse, todo lo que se saltó sigue sin ejecutarse. El autor de claude-quota-guard.py ha publicado la pieza que faltaba, quota-catchup.py, para decidir qué relanzar tras la recuperación.

El guardián se coloca delante de 15 de los plists de ~/Library/LaunchAgents. Mientras el circuito está abierto, cada trabajo que arranca devuelve exit 0 sin ejecutar nada y deja un marcador CLAUDE_QUOTA_JOB_SKIPPED en stderr con la etiqueta y los segundos restantes. El fallo de fondo es que launchd no reintenta por su cuenta: espera al siguiente StartCalendarInterval. Si el trabajo de las 9:00 se saltó por cuota y esta se recupera a las 10:00, pero el siguiente hueco es mañana a las 9:00, se pierde un día entero.

Tres filtros encadenados con AND

find_candidates recorre los plists ordenados y solo acepta un trabajo como candidato si supera tres condiciones a la vez. La primera, is_guarded, es una comparación de cadenas sobre ProgramArguments buscando la presencia de claude-quota-guard: sirve para no arrastrar trabajos cron normales que nada tienen que ver con la cuota. La segunda, latest_marker_is_today_skip, descarta lo que ya se ejecutó y los marcadores antiguos. La tercera, calendar_slot_passed, es la interesante.

Si el plist declara StartInterval, devuelve falso: esos trabajos se repiten solos en el siguiente intervalo y no necesitan rescate. Para los de calendario recorre todas las entradas y va acumulando con un OR si alguna ha pasado ya hoy. El autor avisa del error clásico de quedarse con el veredicto de la primera entrada o de la última: con huecos a las 9:00 y a las 18:00 evaluados a las 13:00, la respuesta correcta es que sí es candidato, porque el de la mañana ya pasó. Un caso real con varios huecos es com.shun.daily-brief.plist, con entradas a las 8:00 y a las 10:30.

El timeout que se quedó corto

El relanzamiento pasa por kick_and_wait, que lanza launchctl kickstart y sondea hasta que el trabajo sale de la gestión de launchd. El valor inicial era 1200 segundos y en producción no llegaba. Una medición del 21 de agosto dejó claro que las rutas de generación con claude, como affameba-gen, pasan de los 20 minutos, así que el número bueno es 2700. Con la configuración equivocada el load average llegó a superar 40, según cuenta el propio autor.

La entrada no enlaza un repositorio concreto con los dos scripts, así que lo aprovechable hoy es el patrón más que el código: si tienes tareas programadas detrás de un cortacircuitos por cuota o por cualquier otro recurso compartido, el cierre del circuito es la parte fácil, y la política de recuperación es donde se decide si el sistema se comporta o se atropella a sí mismo. Queda por ver si el autor publica los ficheros o si esto se queda en descripción de diseño.