Skip to content
cronpad
Retries and failures / Retries

Retries

When an attempt fails with a retryable outcome (a 5xx response, a timeout, a network error), cronpad waits and tries again, up to max_attempts tries in total. Waits grow exponentially by default and include random jitter so that many failing jobs don’t retry in lockstep. A fatal outcome (such as a 404) ends the run immediately.

Retry policy

"retry": {
  "max_attempts": 3,
  "backoff": "exponential",
  "initial_interval": "10s",
  "max_interval": "10m",
  "multiplier": 2.0,
  "jitter": 0.2
}
FieldDefaultDescription
max_attempts3Total tries including the first. 1 disables retries. Capped at 10 on cronpad Cloud.
backoffexponentialexponential or fixed.
initial_interval10sWait before the first retry (and every retry with fixed).
max_interval10mUpper bound for any single wait, including Retry-After values.
multiplier2.0Growth factor for exponential.
jitter0.2Each wait is randomized by ±20%. 0 disables jitter.

Server-wide defaults live in [retry.defaults].

Wait times

Retry n waits min(initial_interval × multiplier^(n−1), max_interval), then ±jitter, with the final wait capped at max_interval.

With max_attempts: 6 and the other defaults:

AttemptWaits before it (before jitter)Elapsed since first attempt
0 (first)—0
110 s~10 s
220 s~30 s
340 s~1 m 10 s
480 s~2 m 30 s
5160 s~5 m 10 s

If the endpoint sends Retry-After with a 429 or 503, cronpad waits that long instead (capped at max_interval).

What gets retried

Whether an outcome is retryable depends on the sink:

  • Webhooks: retry_on, by default 5xx, 408, 429, network errors and timeouts. See Webhooks.
  • Commands: retry_exit_codes and timeouts. See Commands.

While a run is retrying

  • The run’s status is deferred, with next_attempt_at set.
  • Retries never delay the job’s next scheduled run, unless the job uses overlap_policy: skip_if_running (Misfires and overlap).
  • Retries are durable: they’re queued in the queue file and tracked in the database, so a restart doesn’t lose them.
  • Every attempt is listed on the run’s page with its outcome and response.

Retrying by hand

A run that ended failed can be retried with Retry on the run page or POST /api/v1/runs/{id}/retry. This creates a new run with trigger = retry_manual for the same scheduled time and a new run ID (and therefore a new idempotency key). Repeated manual-retry requests for that occurrence coalesce into the same retry run; an exhausted manual retry returns 409 conflict.