Skip to content
cronpad
Concepts / Jobs, runs and attempts

Jobs, runs and attempts

A job says what to do and when. Each time it’s due, that is an occurrence, recorded as one run. Each try at delivering a run is an attempt. A run that fails twice and then succeeds is one run with three attempts.

Workspaces

Everything belongs to a workspace: jobs, API keys, secrets, alert channels and rules. Every user gets a personal workspace when they first sign in. API keys are bound to one workspace, so a key can never see another workspace’s jobs.

Jobs

A job has:

PartExampleDocs
Schedule + timezoneevery weekday at 9am, Europe/LondonSchedules
SinkWebhook to https://api.example.com/reportsSinks
Retry policy3 attempts, exponential backoff from 10 sRetries
Timeout30s per attempt
Misfire and overlap policiesfire_once, allowMisfires and overlap
Auto-disable threshold20 consecutive failed runsAuto-disable
Tags["reports","billing"]Used by alert rules and filters

Job states

StateMeaningHow it gets thereHow it leaves
activeScheduled and firingCreated, resumed or re-enabledPause, auto-disable, schedule exhausted
pausedNot firing; you paused itPOST /jobs/{id}/pausePOST /jobs/{id}/resume
disabledNot firing; cronpad stopped it after too many consecutive failuresAuto-disablePOST /jobs/{id}/enable (resets the failure counter)
completedSchedule has no more occurrences (one-off job fired, count or until reached)AutomaticEdit the schedule

Deleting a job removes it from scheduling immediately. Its run history stays until it ages out under the retention policy.

Every edit increments the job’s version. Occurrences already queued with an older version are dropped, so an edit takes effect from the next fire time, never with a mix of old and new settings.

Runs

A run is one occurrence: “this job, scheduled for this moment”. Runs are created for scheduled fires, for Run now (trigger = manual) and for manual retries of a failed run (trigger = retry_manual).

Run states

           claim                 success
scheduled ──────▶ running ─────────────────────▶ succeeded
                    │  retryable failure, attempts left
                    ├──────────────────────────▶ deferred ── backoff ──▶ running …
                    │  fatal failure, or no attempts left
                    └──────────────────────────▶ failed
scheduled ── missed during downtime, policy says skip ──▶ skipped
scheduled ── job paused, edited or deleted first ─────▶ cancelled

Run timing fields

FieldMeaning
scheduled_atThe moment the run was supposed to start. Never changes, even across retries.
claimed_atWhen the dispatcher took it from the queue.
started_atWhen the first attempt began.
finished_atWhen the final attempt ended.
start_lag_msstarted_at − scheduled_at. The number cronpad’s reliability is judged on.
e2e_msfinished_at − scheduled_at, including retries.
sla_breachedtrue if start_lag_ms exceeded the SLA threshold. See Delivery guarantees.

Attempts

An attempt records one delivery try: start and end time, duration, outcome (success, retryable, fatal, timeout), HTTP status or exit code, error message, a request summary (POST https://api.example.com/reports (412 bytes)) and a truncated response body.

By default, response bodies are kept only for attempts that didn’t succeed, and only for 7 days. See Data retention.

Why runs and attempts are separate

Reliability questions are about runs (“did the 09:00 run succeed, and was it on time?”). Debugging questions are about attempts (“what did the second try get back?”). Keeping them apart keeps run queries fast for dashboards and alerts, and lets the bulky attempt data expire sooner.