-
Notifications
You must be signed in to change notification settings - Fork 1
Open
Labels
featureNew feature or requestNew feature or request
Description
Implementation Order: 3 of 8
Depends on: #29 (models), #30 (CRUD API)
Feature: Schedules — Recurring automated tasks for AI agent teams
Summary
Implement the scheduler engine: a background goroutine that evaluates cron expressions every minute and triggers due schedules. This is the core timing mechanism.
Architecture
API Server starts
└── scheduler.Start(db, triggerFunc)
└── goroutine: tick every 60s
├── SELECT * FROM schedules WHERE enabled=true AND next_run_at <= now()
├── For each due schedule:
│ ├── go triggerFunc(schedule) ← parallel, non-blocking
│ └── UPDATE next_run_at to next occurrence
└── Sleep until next tick
Key Requirements
Non-blocking
- CRITICAL: The scheduler MUST NOT block the API server. It runs in its own goroutine.
- Each schedule execution runs in a separate goroutine — 10 schedules can run in parallel without issues.
- The scheduler ticker continues checking every minute regardless of running executions.
Parallel Executions
- If a schedule triggers while a previous execution is still running, a new parallel execution starts (no skip, no queue).
- Each execution is fully independent with its own ScheduleRun record.
Cron Library
- Use a Go cron parsing library (e.g.,
github.com/robfig/cron/v3or similar) to:- Parse and validate cron expressions
- Calculate
next_run_atgiven a cron expression + timezone
Timezone Support
- All cron evaluations must respect the schedule's configured timezone.
- Store
next_run_atin UTC internally, but evaluate using the schedule's timezone.
Package Structure
internal/scheduler/
├── scheduler.go // Start(), Stop(), tick loop
├── cron.go // ParseCron(), NextRun() helpers
└── scheduler_test.go // Unit tests
Graceful Shutdown
scheduler.Stop()must cleanly stop the ticker- Wire into the API server's shutdown handler (already exists for NATS, Docker, etc.)
Acceptance Criteria
- New
internal/scheduler/package -
Start(db, executeFn)launches background goroutine - Ticks every 60 seconds, queries for due schedules
- Each due schedule triggers
executeFnin a new goroutine - Updates
next_run_atafter triggering - Handles timezone correctly
-
Stop()for graceful shutdown - Wired into
cmd/api/main.gostartup and shutdown - Unit tests for cron parsing and next-run calculation
- Integration test: create schedule due in past → verify it triggers on next tick
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
featureNew feature or requestNew feature or request
Type
Projects
Status
Todo