Skip to content

Cron jobs

In this guide you schedule a recurring command for an app, for example a nightly cleanup, and check that it runs.

  • An app that has been deployed at least once. Runs are skipped until then.
  • The developer role to create, change, run jobs and read their output. Any team member can list jobs.
Terminal window
PANEL=https://panel.example.com
H='Authorization: Bearer gsl_xxxxxxxxxxxxxxxx'
J='Content-Type: application/json'

Schedules are 5-field cron expressions (*/15 * * * *, 0 3 * * mon-fri) or @hourly, @daily, @weekly, @monthly, @yearly. They’re evaluated in UTC.

Terminal window
curl -s "$PANEL/apps/42/cron/preview?schedule=0%203%20*%20*%20*" -H "$H"
# → the next 5 run times, or 400 invalid_schedule with the reason
Terminal window
curl -sX POST $PANEL/apps/42/cron/ -H "$H" -H "$J" -d '{
"name": "nightly-cleanup",
"schedule": "0 3 * * *",
"command": "./current/app cleanup --older-than 30d",
"timeoutSeconds": 600
}'
Field Notes
name Up to 100 characters.
schedule As above.
command Up to 4000 characters. Runs like a console command: as the app’s Linux user, in its directory, with its env vars and toolchain on the path.
timeoutSeconds 1 to 3600, default 300. The run is killed and marked timed_out after that.
enabled Default true.

An app can have at most 20 jobs.

Terminal window
curl -sX POST $PANEL/apps/42/cron/{jobId}/run -H "$H"

The response is the run. Its execId streams live output on the /ws/apps/42/exec/{execId} WebSocket, like the console. You get 409 if a run of this job is still going.

Terminal window
curl -sX PATCH $PANEL/apps/42/cron/{jobId} -H "$H" -H "$J" -d '{"enabled": false}'
curl -sX DELETE $PANEL/apps/42/cron/{jobId} -H "$H" # also deletes its runs

The worker checks for due jobs every 30 seconds. Each slot is claimed atomically, so a job never runs twice even with several workers. A slot missed while the worker was down runs once when it comes back. A run is skipped while the previous one is still running, or while the app has never been deployed. A run lost to a worker restart is marked failed after its timeout plus 5 minutes.

Terminal window
curl -s $PANEL/apps/42/cron/ -H "$H" | jq '.results[] | {name, nextRunAt, lastRunAt, lastStatus}'
curl -s $PANEL/apps/42/cron/{jobId}/runs -H "$H" \
| jq '.results[0] | {status, exitCode, output}'

Runs (the last 50) have a status of running, succeeded, failed, timed_out or skipped, an exitCode, and the last 200 lines of output. Output can contain secrets, which is why reading runs needs the developer role.