Scheduler API
Manage scheduled jobs for automated task execution. Supports cron, one-time (at), and recurring (every) schedules with missed-job detection.
Overview
The scheduler runs as a gen_server with an ETS-backed job store. Jobs are attributed to the user who created them and dispatch tasks to workers at the scheduled time.
| Schedule Type | Description | Use Case |
|---|---|---|
cron | Cron expression (5-field) | Periodic tasks on a calendar schedule |
every | Interval in milliseconds | Recurring tasks at fixed intervals |
at | One-time timestamp (ms) | Delayed single execution |
Create a Scheduled Job
POST /api/v1/schedulesCreate a new scheduled job. Requires admin permissions.
Cron Schedule
{
"name": "Daily health check",
"prompt": "Check system health and report any issues",
"cron": "0 9 * * *",
"model": "glm-5.1",
"opts": {}
}Every Schedule
{
"name": "Monitor queue depth",
"prompt": "Check ZMQ queue depth and alert if > 100",
"every": 300000,
"model": "glm-5.1"
}One-time Schedule
{
"name": "Deploy notification",
"prompt": "Announce deployment completion",
"at": 1716192000000,
"delete_after_run": true
}Natural Language Schedule
Instead of specifying cron, every, or at directly, use schedule for natural language:
{
"name": "Weekly report",
"prompt": "Generate weekly system report",
"schedule": "every monday at 9am"
}Request Fields
| Field | Required | Description |
|---|---|---|
prompt | Yes | Task prompt to send when the job fires |
name | No | Human-readable job name |
cron | One of cron/every/at | Cron expression (e.g. 0 */5 * * *) |
every | One of cron/every/at | Interval in milliseconds (must be positive) |
at | One of cron/every/at | Unix timestamp in milliseconds |
schedule | Alternative to cron/every/at | Natural language schedule |
model | No | Model to use for the task |
opts | No | Additional options passed to the task |
delete_after_run | No | Auto-delete after execution (at jobs only, default: false) |
Response
{
"status": "ok",
"id": 42,
"next_run": 1716192000000
}Error Responses
| Code | Description |
|---|---|
| 400 | Missing prompt, invalid schedule, or invalid cron expression |
| 403 | Non-admin user |
List Scheduled Jobs
GET /api/v1/schedulesReturns all scheduled jobs. Admin-only; non-admin users receive an empty list.
Response
{
"items": [
{
"id": 1,
"name": "Daily health check",
"schedule_type": "cron",
"cron_expr": "0 9 * * *",
"enabled": true,
"next_run": 1716192000000,
"last_run": 1716105600000,
"consecutive_errors": 0,
"created_at": 1716000000000
},
{
"id": 2,
"name": "Queue monitor",
"schedule_type": "every",
"interval_ms": 300000,
"enabled": true,
"next_run": 1716192300000,
"last_run": 1716192000000,
"consecutive_errors": 0,
"created_at": 1716000000000
}
],
"total": 2,
"page": 1,
"per_page": 50
}Supports pagination via ?page=N&per_page=M query parameters.
Get Job Detail
GET /api/v1/schedules/:idReturns details for a specific scheduled job.
Response
{
"id": 1,
"name": "Daily health check",
"schedule_type": "cron",
"cron_expr": "0 9 * * *",
"prompt": "Check system health and report any issues",
"model": "glm-5.1",
"enabled": true,
"next_run": 1716192000000,
"last_run": 1716105600000,
"last_result": "ok",
"consecutive_errors": 0,
"user_uuid": "user_abc123",
"created_at": 1716000000000
}Error Responses
| Code | Description |
|---|---|
| 400 | Invalid job ID |
| 404 | Job not found |
Delete a Scheduled Job
DELETE /api/v1/schedules/:idCancel and remove a scheduled job. Requires admin permissions.
Response
{
"status": "deleted"
}Error Responses
| Code | Description |
|---|---|
| 403 | Non-admin user |
| 404 | Job not found |
| 409 | Job is currently running |
Pause a Job
POST /api/v1/schedules/:id/pausePause a scheduled job without deleting it. The job will not fire until resumed. Requires admin permissions.
Response
{
"status": "paused"
}Resume a Job
POST /api/v1/schedules/:id/unpauseResume a paused job. Requires admin permissions.
Response
{
"status": "active"
}Manually Trigger a Job
POST /api/v1/schedules/:id/runTrigger immediate execution of a scheduled job, regardless of its schedule. Requires admin permissions.
Response
{
"status": "dispatched"
}Error Responses
| Code | Description |
|---|---|
| 400 | Job is disabled (paused), unpause first |
| 404 | Job not found |
| 409 | Job is already running |
Missed-Job Detection
The scheduler detects jobs that missed their scheduled time during downtime. On startup:
- All stored jobs are loaded from ETS
- Jobs with
next_runin the past are identified - Up to 5 missed jobs are dispatched with 5-second stagger
- Jobs with 10+ consecutive errors are automatically paused
This ensures tasks are not permanently lost after server restarts.
Limits
| Parameter | Default | Description |
|---|---|---|
max_scheduled_jobs | 1000 | Maximum active jobs |
max_consecutive_errors | 10 | Auto-pause threshold |
max_catchup_runs | 5 | Missed jobs dispatched on startup |
catchup_stagger_ms | 5000 | Delay between catchup dispatches |
timer_clamp_ms | 60000 | Maximum timer precision |
max_dispatch_per_tick | 5 | Jobs dispatched per scheduler tick |
User Attribution
Each job records the user_uuid of the creating user (captured at creation time in the HTTP process). When the job fires, the task is dispatched with this user_uuid, ensuring proper ownership of results.
Cron Expression Format
5-field cron expressions are supported:
┌───────────── minute (0-59)
│ ┌───────────── hour (0-23)
│ │ ┌───────────── day of month (1-31)
│ │ │ ┌───────────── month (1-12)
│ │ │ │ ┌───────────── day of week (0-6, 0=Sunday)
│ │ │ │ │
* * * * *Examples:
| Expression | Meaning |
|---|---|
0 9 * * * | Every day at 9:00 |
*/5 * * * * | Every 5 minutes |
0 */2 * * * | Every 2 hours |
0 9 * * 1 | Every Monday at 9:00 |
0 0 1 * * | First of every month at midnight |