feat(automations): fire trigger.schedule on a cron schedule (#3653)#3726
Conversation
trigger.schedule was a catalog stub the engine never fired. The engine now arms a croner job per enabled schedule automation in load() (rescheduleCron), so create/update/enable/disable/reload all re-arm correctly (load() is called from reloadAutomations after every CRUD). Each job calls engine.onSchedule(id) → buildScheduleContext → graph run, honoring the per-automation cooldown. - New buildScheduleContext in triggerContext.ts (no mesh payload). - CronScheduler is injectable (EngineServiceOptions.cron) so tests use a fake and assert registration/cancellation without real timers; prod uses croner. - Invalid/missing crons are skipped + logged, and rejected at save (validateForm via cron-validator). Tests: arm-per-automation + onSchedule fires the graph (incl. via the registered cron callback), invalid cron not armed, reload stops old + re-arms, cooldown honored, buildScheduleContext shape. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VBLhGGNh35oMwTL53va1Y5
|
Claude finished @Yeraze's task —— View job PR Review: feat(automations): fire trigger.schedule on a cron scheduleTasks:
SummaryThis is a clean, well-scoped implementation. The core design choices are sound and the tests are comprehensive. Below are a few observations worth considering, ordered by severity. Potential Issue: Cron Validator Mismatch Between Frontend and BackendFile: The frontend validates using A cron expression accepted by the frontend form could be rejected silently by the backend's Suggestion: Either add a server-side validation step in the save route that uses the same Minor:
|
First of the two documented post-#3721 follow-ups (
AUTOMATION_ENGINE_PLAN.md§11).Problem
trigger.schedulewas a catalog-only stub — the engine never fired it. Automations with a schedule trigger could be built and dry-run in the Test panel, but never ran live.Change
The engine now arms a croner job per enabled
trigger.scheduleautomation insideload()(rescheduleCron()). BecausereloadAutomations()→load()runs after every CRUD, create/update/enable/disable/delete/reload all re-arm correctly (old jobs stopped first — no stale or duplicate jobs). Each job callsengine.onSchedule(id)→buildScheduleContext→ graph run, honoring the per-automation cooldown.buildScheduleContext(no mesh payload, no subject node).EngineServiceOptions.cron: CronScheduler) — prod usescronScheduler.ts(croner); tests use a fake to assert registration/cancellation without real timers.validateFormviacron-validator, matching the rest of the app:{ seconds:false, alias:true, allowBlankDay:true }).Tests
Arm-one-job-per-automation +
onSchedulefires the graph (directly and via the registered cron callback), invalid cron not armed, reload stops the old job and re-arms, cooldown honored, andbuildScheduleContextshape. Full suite 7513 passed, 0 failures; tsc + build clean.Follow-up still open
The second §11 item — smarter
{{ }}token entry (highlight trigger/var tokens, flag unrecognized) — is a separate upcoming PR.🤖 Generated with Claude Code