# Scheduler — Cron expression parsing, matching, scheduling Tag: `scheduler`. Grupo de funciones para trabajar con expresiones cron: parsear, validar coincidencias, calcular proximo run, traducir a lenguaje humano. Lo consume `apps/dag_engine` + `cpp/apps/dag_engine_ui` (tab Schedule). Crece a medida que se anaden nuevos formatos (Quartz, k8s CronJob, etc.). Filtro MCP: `mcp__registry__fn_search query="" tag="scheduler"`. ## Funciones del grupo | ID | Firma corta | Que hace | |---|---|---| | [parse_cron_expr_go_core](../../functions/core/parse_cron_expr.md) | `ParseCronExpr(expr string) (CronSchedule, error)` | Parsea expresion cron de 5 campos a struct expandido. Soporta `*`, rangos, listas, pasos y aliases `@hourly/@daily/@weekly/@monthly/@yearly`. | | [cron_match_go_core](../../functions/core/cron_match.md) | `CronMatch(s CronSchedule, t time.Time) bool` | True si un instante coincide con un schedule. Compara los 5 campos. | | [next_cron_time_go_core](../../functions/core/next_cron_time.md) | `NextCronTime(s CronSchedule, after time.Time) time.Time` | Proxima ejecucion despues de un instante. Salta minuto a minuto. Zero time si no hay match en 366 dias. | | [cron_explain_go_core](../../functions/core/cron_explain.md) | `CronExplain(expr string) string` | Traduce expresion cron a frase humana corta (`"every 15 minutes"`, `"daily at 09:00"`, `"weekdays at HH:MM"`). | ## Ejemplo canonico end-to-end Trabajar con un schedule completo: parsear, calcular proximo run, explicarlo al usuario. ```go package main import ( "fmt" "time" "fn-registry/functions/core" ) func main() { expr := "*/15 * * * *" // 1. Parsear sched, err := core.ParseCronExpr(expr) if err != nil { panic(err) } // 2. Proximo run next := core.NextCronTime(sched, time.Now()) fmt.Printf("next run: %s\n", next.Format(time.RFC3339)) // 3. Explicacion humana fmt.Printf("schedule: %s (%s)\n", expr, core.CronExplain(expr)) // -> schedule: */15 * * * * (every 15 minutes) // 4. Verificacion puntual if core.CronMatch(sched, time.Now()) { fmt.Println("would trigger now") } } ``` ## Fronteras del grupo NO cubre: - Persistencia de schedules (vive en BD de quien lo use: `apps/dag_engine/store/`). - Spawn/wait de procesos (eso es `process_*_go_infra`). - Sintaxis Quartz extendida con `?` o anos. Solo soporta los 5 campos estandar + aliases `@hourly/@daily/@weekly/@monthly/@yearly`. - Timezones — todo se evalua en `time.Local` del proceso. Si necesitas TZ explicita, parsea fuera y traduce. - Sintaxis especial de Kubernetes CronJob (segundos opcionales en el primer campo). - DAG orchestration / DAG runs (consume estas funciones via `apps/dag_engine`). ## Prerequisitos - Go stdlib. Sin dependencias externas en ninguna funcion del grupo. - Tipo compartido `cron_schedule_go_core` (struct con `Minute/Hour/Day/Month/Weekday` como `[]int` expandidos). ## Notas - `cron_match` esta tageada `pendiente-usar` — sin consumidores actuales aparte del propio paquete. Si se incorpora a `next_cron_time` como optimizacion -> quitar tag. - `cron_explain` mantiene contrato simple: si el patron no encaja en los reconocidos, devuelve el expr crudo sin error. Apto para UI fallback. - Para anadir nueva funcion al grupo: anadir tag `scheduler` al `tags:` del frontmatter, anadir fila a la tabla arriba, actualizar `N` en `docs/capabilities/INDEX.md`. ## Consumidores actuales - `apps/dag_engine` — `parse_cron_expr_go_core`, `next_cron_time_go_core` (+ `cron_ticker_go_infra` adyacente). - `cpp/apps/dag_engine_ui` — tab Schedule consume `/api/dags` expuesto por dag_engine; via backend usa estas funciones. - Candidato futuro: `cron_explain_go_core` en `dag_engine` `/api/dags` (anadir campo `schedule_human` al JSON response) para que la UI no tenga que duplicar logica.