Retries
Automatic exponential backoff and configurable retry policies
When a handler fails, Restaq automatically schedules a retry—no queue infrastructure, no manual intervention needed.
Default retry policy
By default, a failed execution will be retried up to 3 times total (attempt 1, 2, and 3), with exponential backoff between attempts:
Attempt 1: initial try (no backoff)
Attempt 2: retry after ~1 second (1000ms)
Attempt 3: retry after ~2 seconds (2000ms)The backoff formula is:
delay = min(1000 * 2^(attempt - 1), 30_000) millisecondsThis means the delay doubles each time, capped at 30 seconds. After the 3rd attempt fails, the execution is marked as failed and stops retrying.
Customizing retry policy
You can override the retry policy when creating the relay:
const relay = restaq({
database: pool,
plugins: [stripe()],
retry: {
maxAttempts: 5, // Try up to 5 times
backoff: (attempt) => {
// Custom backoff: linear instead of exponential
return attempt * 1000; // 1s, 2s, 3s, 4s
},
},
});How retries work
- Handler is called with the original event data.
- If any step fails (throws), the execution status becomes
failedand the error is recorded. - If
attempt < maxAttempts, a timer schedules a retry after the backoff delay. - On retry,
attemptis incremented and the handler runs again. - Any previously completed steps are cached and skipped—only failed/uncompleted steps run.
In-process coordination only
Important: Retry scheduling is in-process only. Each server instance can retry its own in-flight executions, but there's no database-level lock yet to stop two instances from retrying the same execution at once — see in-process execution locking for the mechanism and what a multi-instance deployment needs instead.
Manual retry
You can also manually retry a failed execution at any time via the API:
await restaq.retryExecution(executionId);Or via the CLI:
relay inspect <executionId> # Check the status
relay events list # Find the execution IDThen call restaq.retryExecution(executionId) from a management API route in your app to trigger the retry — see Management endpoints for example routes.
Viewing retry history
The logs and step history show exactly when each retry was scheduled and what happened on each attempt:
$ relay inspect <executionId>
Status: completed
Attempt: 2
Logs:
[system] event ingested
[handler] Started processing...
[system] retrying (attempt 2, scheduled)
[handler] Processing again...
✓ completedEach execution keeps its full lifecycle, so you can trace why it failed and why it eventually succeeded.