Skip to main content
An http job calls a path on your app on a cron schedule instead of running a command. It is the Levelrail version of a scheduled function: the app keeps its handler, the control plane keeps the clock. If the app is asleep (sleep when idle), the control plane wakes it, waits until it accepts connections, then makes the call. Http jobs are ordinary scheduled jobs with mode: http, so they share the Jobs tab, the CLI, the API, run history, retries, catch-up and alerts.

Create one

Dashboard: App > Jobs > Create job, set Where it runs to HTTP call to the app, then a path, method and schedule. The dialog lists the next five runs in the job’s time zone before you save. CLI:
API: POST /api/v1/apps/{name}/jobs with

Schedules

Five fields (minute hour day-of-month month day-of-week) or one of @hourly, @daily, @midnight, @weekly, @monthly, @yearly. The schedule is read on the wall clock of the job’s IANA time zone. A wall time skipped by a daylight saving jump runs once, an hour later. A wall time repeated by a fall-back runs once.

What a call looks like

The control plane sends the method and path to the app’s published port, with X-Job-Run (the run ID), X-Job-Name and, for background jobs, X-Job-Background: 1. A body, if set, is sent as application/json. Any 2xx answer is a success. Anything else is a failure and is retried with doubling backoff up to the job’s retries. The HTTP status is stored on the run (shown as HTTP 200 in history) with the first part of the response body, capped by APP_JOBS_MAX_OUTPUT_BYTES. The path must start with a single /; the call never leaves the app.

Overlap

A schedule is single-flight per occurrence: the control plane persists which cron occurrence it handled before it runs it, so a restart never runs the same occurrence twice and never silently loses one. A run that was in flight during a restart is marked interrupted and is not re-run. Missed occurrences follow the job’s catch-up policy.

Background functions

Turn on Background job (--background, "background": true) for work that outlives a normal request. Your handler answers 202 straight away, or just keeps the connection open and works; either way the control plane, not the caller, waits for the outcome. It holds the call (and the wake) for up to APP_JOBS_BACKGROUND_TIMEOUT (default 15m) unless the job sets its own timeout, then records success, failure or timeout in the run history. Triggering a job with Run now (POST .../jobs/{id}/run) always returns 202 with a run ID immediately, whatever the job’s duration.

Pause, resume, run now, history

levelrail-cli jobs pause|resume <app> <job> (or the Enabled switch) stops and restarts the schedule without a backlog: resuming does not replay what was paused. jobs run fires a job now. jobs history <app> [job] and the history table list status, duration, HTTP status, attempts and the response body. The last APP_JOBS_HISTORY_KEEP runs per job are kept.

Alerts

A failed run raises the existing job alert kinds, so add one rule per job and it reaches your notification channels like any other alert:
scheduled_task_missed and scheduled_task_running_long work the same way.

Limits

The rest are listed with scheduled jobs.

Not covered

Http jobs cannot yet be declared in app.yaml, and the call carries no custom headers. Use the dashboard, CLI or API to manage them.
Last modified on October 21, 2026