Skip to content

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 TypeDescriptionUse Case
cronCron expression (5-field)Periodic tasks on a calendar schedule
everyInterval in millisecondsRecurring tasks at fixed intervals
atOne-time timestamp (ms)Delayed single execution

Create a Scheduled Job

POST /api/v1/schedules

Create a new scheduled job. Requires admin permissions.

Cron Schedule

json
{
  "name": "Daily health check",
  "prompt": "Check system health and report any issues",
  "cron": "0 9 * * *",
  "model": "glm-5.1",
  "opts": {}
}

Every Schedule

json
{
  "name": "Monitor queue depth",
  "prompt": "Check ZMQ queue depth and alert if > 100",
  "every": 300000,
  "model": "glm-5.1"
}

One-time Schedule

json
{
  "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:

json
{
  "name": "Weekly report",
  "prompt": "Generate weekly system report",
  "schedule": "every monday at 9am"
}

Request Fields

FieldRequiredDescription
promptYesTask prompt to send when the job fires
nameNoHuman-readable job name
cronOne of cron/every/atCron expression (e.g. 0 */5 * * *)
everyOne of cron/every/atInterval in milliseconds (must be positive)
atOne of cron/every/atUnix timestamp in milliseconds
scheduleAlternative to cron/every/atNatural language schedule
modelNoModel to use for the task
optsNoAdditional options passed to the task
delete_after_runNoAuto-delete after execution (at jobs only, default: false)

Response

json
{
  "status": "ok",
  "id": 42,
  "next_run": 1716192000000
}

Error Responses

CodeDescription
400Missing prompt, invalid schedule, or invalid cron expression
403Non-admin user

List Scheduled Jobs

GET /api/v1/schedules

Returns all scheduled jobs. Admin-only; non-admin users receive an empty list.

Response

json
{
  "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/:id

Returns details for a specific scheduled job.

Response

json
{
  "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

CodeDescription
400Invalid job ID
404Job not found

Delete a Scheduled Job

DELETE /api/v1/schedules/:id

Cancel and remove a scheduled job. Requires admin permissions.

Response

json
{
  "status": "deleted"
}

Error Responses

CodeDescription
403Non-admin user
404Job not found
409Job is currently running

Pause a Job

POST /api/v1/schedules/:id/pause

Pause a scheduled job without deleting it. The job will not fire until resumed. Requires admin permissions.

Response

json
{
  "status": "paused"
}

Resume a Job

POST /api/v1/schedules/:id/unpause

Resume a paused job. Requires admin permissions.

Response

json
{
  "status": "active"
}

Manually Trigger a Job

POST /api/v1/schedules/:id/run

Trigger immediate execution of a scheduled job, regardless of its schedule. Requires admin permissions.

Response

json
{
  "status": "dispatched"
}

Error Responses

CodeDescription
400Job is disabled (paused), unpause first
404Job not found
409Job is already running

Missed-Job Detection

The scheduler detects jobs that missed their scheduled time during downtime. On startup:

  1. All stored jobs are loaded from ETS
  2. Jobs with next_run in the past are identified
  3. Up to 5 missed jobs are dispatched with 5-second stagger
  4. Jobs with 10+ consecutive errors are automatically paused

This ensures tasks are not permanently lost after server restarts.

Limits

ParameterDefaultDescription
max_scheduled_jobs1000Maximum active jobs
max_consecutive_errors10Auto-pause threshold
max_catchup_runs5Missed jobs dispatched on startup
catchup_stagger_ms5000Delay between catchup dispatches
timer_clamp_ms60000Maximum timer precision
max_dispatch_per_tick5Jobs 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:

ExpressionMeaning
0 9 * * *Every day at 9:00
*/5 * * * *Every 5 minutes
0 */2 * * *Every 2 hours
0 9 * * 1Every Monday at 9:00
0 0 1 * *First of every month at midnight

Released under the MIT License.