Cron (Periodic Tasks)
Cron tasks let you trigger a function on a repeating schedule or run it once when a deployment becomes active. They are a first-class part of the deployment configuration — no extra infrastructure is needed.
Defining a cron task
Add one or more [[cron]] sections to your deployment.toml:
[[cron]]
name = "daily-cleanup"
ffqn = "myapp:tasks/jobs@1.0.0.daily-cleanup"
params = '["archive", 30]' # JSON array; defaults to []
schedule = "@daily"| Field | Type | Required | Description |
|---|---|---|---|
name | string | yes | Unique name within the deployment |
ffqn | string | yes | FFQN of the function to call |
params | JSON array string | no | Parameters passed to the function on every tick (default: []) |
schedule | string | yes | Cron expression or named shorthand (see below) |
Schedule syntax
The schedule field accepts standard five-field cron expressions or one of the named shorthands:
| Value | Equivalent / Meaning |
|---|---|
@once | Run exactly once when the deployment is activated |
@hourly | 0 * * * * — at minute 0 of every hour |
@daily | 0 0 * * * — at midnight every day |
@weekly | 0 0 * * 0 — at midnight every Sunday |
@monthly | 0 0 1 * * — at midnight on the 1st of each month |
@yearly | 0 0 1 1 * — at midnight on 1 January |
"*/5 * * * *" | Every 5 minutes (custom expression) |
Fields in a cron expression are: minute hour day-of-month month day-of-week.
How it works
When a deployment becomes active, Obelisk creates a cron scheduler execution for each [[cron]]
entry. The scheduler runs as a long-lived internal workflow:
- On each tick it computes the next scheduled time and persists the schedule to the execution log.
- It sleeps until that time using a durable persistent sleep.
- It submits the target function as a top-level execution with the configured
params. - It loops back to step 1.
Because the scheduler is itself a durable execution, it survives server restarts and crashes without missing ticks.
The @once shorthand submits the target function once immediately and then the scheduler execution
finishes.
Relationship to deployments
During server startup or a hot-redeploy, Obelisk hashes each [[cron]] entry's configuration —
name, ffqn, params, and schedule — with SHA-256 to produce a content digest. From that
digest it derives a deterministic execution ID, so a given cron configuration always maps to exactly
one seed execution.
Obelisk then upserts only missing seed executions: if a seed execution with that ID already exists in the database, it is reused as-is; otherwise a new one is created. This means an unchanged cron entry survives restarts and redeployments without interruption. Most notably, the cron will not fire again immediately after a redeploy — the existing seed execution is reused with its full event history, so the next tick is computed from where it left off.
Each active [[cron]] entry gets its own executor bound to the ComponentId that carries the
content digest. The executor picks up — and continues running — whichever seed execution matches
that digest.
Cron entries that are removed from deployment.toml are simply left without an executor: their
old seed executions remain in the database in a Pending state indefinitely, unless a future
deployment reactivates them by including a matching cron configuration again.
Viewing cron executions
Cron scheduler executions appear in the Web UI and via the API like any other execution. They use an
FFQN derived from the target: obelisk:schedule/<name>.<target-function>-cron.
obelisk execution submit --follow myapp:tasks/jobs@1.0.0.daily-cleanup '["archive", 30]'
You can also list all executions for a cron function after exporting OBELISK_API_TOKEN as
described in Authentication:
curl "127.1:5005/v1/executions?ffqn_prefix=obelisk:schedule/" -H accept:application/json \
-H "Authorization: Bearer $OBELISK_API_TOKEN"