levelrail-cli jobs, in
app.yaml, and at /api/v1/apps/{name}/jobs. They are the same jobs on every
surface.
Where a job runs
A fresh job gets no published ports and no restart policy, and only the volumes
the app already declares. It runs as the image’s user under the same Docker
guard rules as the app itself. On a multi-node setup the job runs on the node
the app is placed on.
The command is a real argv list with no shell involved. Use
["sh", "-c", "..."] for pipelines. The dashboard form wraps what you type in
sh -c for you. For a fresh job the command replaces the image’s entrypoint, so
what you write is exactly what runs.
Create a job
Dashboard
Open the app, choose Jobs, then Create job. Pick the schedule (daily, weekly or a cron expression), the time zone, and the policies below. Use Run now on a row to try it immediately.CLI
<job> is the job’s name or its ID. jobs logs prints the latest run’s output,
or a specific one with --run RUN_ID.
app.yaml
app.yaml jobs match the list: new ones are
created, changed ones updated in place (keeping their history), and ones you
remove are deleted. A spec job is marked app.yaml in the dashboard and can only
be enabled or disabled there. Jobs you create in the dashboard or CLI are never
touched. A spec with no jobs: key leaves existing jobs alone; jobs: []
removes every spec job.
Jobs created through the API default to
concurrency: allow.
When jobs run, and what survives a restart
The scheduler is level-triggered: each tick it works out which cron occurrence is due from the job’s saved high-water mark and the clock, claims that occurrence in the database, and only then runs it. Because the claim is saved before the command starts:- A control plane restart never runs the same occurrence twice.
- A run that was in flight when the control plane stopped is marked interrupted and its container is removed. It is not retried, since the command may already have done real work.
- If the control plane was down across an occurrence, the job is either run once
(
catchUp: run-once, when the occurrence is inside the lookback window) or recorded as missed (skip). Nothing is dropped silently, and a job that was only just enabled does not backfill.
History and logs
The Jobs tab shows the run history for the app, newest first, with a status filter and a log view per run. The same data is atGET /api/v1/apps/{name}/job-runs and GET .../jobs/{job}/runs/{run}. Each run
records the trigger (schedule, manual or api), attempts, exit code,
duration and node.
Output keeps the last 64 KiB of stdout and stderr. Values of the app’s secrets
(and any env var whose name looks like a password, token, key or DSN) are
replaced with [redacted] before the output is stored.
Output of a fresh job is captured on the control plane’s own node. On a remote
node the run still records its exit code and timing, but not output; use
exec mode when you need the output from a remote node.
Alerts
Create alert rules on a job from Alerts orlevelrail-cli apps alerts create
with --scheduled-task-id <job id>:
They use the same notification channels as every other alert.