Files
egutierrez a9cd28b010 chore: añade directorio dev/ con issues y funciones implementadas
Tracking de issues completados (jupyter tools) y funciones implementadas (specs de diseño ya resueltas).
2026-04-05 18:19:36 +02:00

3.8 KiB

Scheduling / Cron

Gap identificado en el registry. Reimplementar desde cero.

Los pipelines se lanzan manualmente o desde la TUI. No hay scheduling recurrente dentro del registry. Complementario a Dagu — estas funciones son primitivas componibles, no un scheduler completo.

Funciones a implementar

parse_cron_expr

  • Dominio: core
  • Lang: Go
  • Purity: pure
  • Signature: ParseCronExpr(expr string) (CronSchedule, error)
  • Retorno: CronSchedule con campos Minute, Hour, DayOfMonth, Month, DayOfWeek parseados
  • Descripcion: Parser de expresiones cron estandar (5 campos). Soporta *, rangos (1-5), listas (1,3,5), pasos (*/15), y aliases (@hourly, @daily, @weekly, @monthly). No soporta seconds ni years (no es Quartz).
  • Algoritmo:
    1. Check aliases (@hourly → "0 * * * *", etc)
    2. Split por espacios, validar 5 campos
    3. Por campo: expandir * a rango completo, parsear rangos/listas/pasos
    4. Validar limites (minute 0-59, hour 0-23, etc)
  • Deps: strings, strconv, fmt (solo stdlib)
  • Tests:
    • "*/15 * * * *" → minutos [0,15,30,45]
    • "0 9 * * 1-5" → 9am weekdays
    • "@daily" → "0 0 * * *"
    • "0 9 1,15 * *" → dia 1 y 15 a las 9
    • Expresion invalida → error descriptivo
    • Campo fuera de rango → error

next_cron_time

  • Dominio: core
  • Lang: Go
  • Purity: pure
  • Signature: NextCronTime(schedule CronSchedule, after time.Time) time.Time
  • Retorno: Proximo time.Time que cumple el schedule despues de after
  • Descripcion: Calcula la proxima ejecucion de un cron schedule. Avanza minuto a minuto desde after hasta encontrar un match. Limit de 366 dias para evitar loops infinitos en schedules imposibles.
  • Algoritmo:
    1. Truncar after al minuto, avanzar 1 minuto
    2. Check month → si no match, avanzar al primer dia del proximo mes valido
    3. Check day of month y day of week → si no match, avanzar al proximo dia
    4. Check hour → si no match, avanzar a la proxima hora
    5. Check minute → si no match, avanzar al proximo minuto
  • Deps: time
  • Tests:
    • "0 * * * *" desde 14:30 → 15:00
    • "0 9 * * 1" desde viernes → proximo lunes 9:00
    • "0 0 29 2 *" → proximo 29 de febrero
    • Schedule imposible → panic o error despues de limit

cron_ticker

  • Dominio: infra
  • Lang: Go
  • Purity: impure (goroutine + channel + time)
  • Signature: CronTicker(schedule CronSchedule, ctx context.Context) <-chan time.Time
  • Retorno: Channel que emite un time.Time en cada tick del schedule
  • Descripcion: Crea un ticker que emite en los momentos definidos por el cron schedule. Usa time.NewTimer internamente, recalculando el proximo tick despues de cada emision. Se detiene al cancelar el context.
  • Deps: time, context
  • Tests:
    • Ticker con schedule "* * * * *" emite cada minuto (test con clock mock o schedule rapido)
    • Context cancel detiene el ticker
    • Channel se cierra al cancelar

parse_cron_expr (Python)

  • Dominio: core
  • Lang: Python
  • Purity: pure
  • Signature: parse_cron_expr(expr: str) -> dict
  • Retorno: {"minute": list[int], "hour": list[int], "day_of_month": list[int], "month": list[int], "day_of_week": list[int]}
  • Descripcion: Misma semantica que Go. Dict en vez de struct.
  • Tests: Mismos casos que Go

next_cron_time (Python)

  • Dominio: core
  • Lang: Python
  • Purity: pure
  • Signature: next_cron_time(schedule: dict, after: datetime) -> datetime
  • Descripcion: Misma semantica que Go.
  • Tests: Mismos casos que Go

Tipo a implementar

CronSchedule (Go)

  • Dominio: core
  • Lang: Go
  • Algebraic: product
  • Definicion:
    type CronSchedule struct {
        Minute     []int
        Hour       []int
        DayOfMonth []int
        Month      []int
        DayOfWeek  []int
        Raw        string // expresion original
    }