Skip to main content

Timeouts and retries

View Markdown

Two budgets

OptionCovers
attemptTimeoutone attempt, from the moment a worker picks it up
overallTimeoutthe whole run: queue wait plus every attempt

Unbounded retries without an overall budget are rejected by RunOptions, because such a run can live forever. Either bound the attempts or bound the run.

For a flow, attemptTimeout is the budget of one attempt of the whole body and overallTimeout the budget of all of them.

Retry policy

RetryPolicy(
maxAttempts = 5, // 0 = unbounded, then overallTimeout is required
initialInterval = 1.seconds,
backoffCoefficient = 2.0,
maxInterval = 100.seconds,
nonRetryableErrors = setOf("IllegalArgumentException"),
)

Retrying is the orchestrator's job, not yours. The handler just fails; the engine waits, then schedules the next attempt, possibly on a different worker. A handler stops the retrying early by throwing NonRetryableTaskError.

What ends a run

CauseState
attempts exhaustedFailed, with the last error's message
non-retryable errorFailed, on that attempt
attempt budget exceeded on the last attemptTimedOut
overall budget exceededTimedOut
cancel delivered at a heartbeatCancelled
operator terminated itTerminated; no handler code observed it

Remember: RetryPolicy in RunOptions is the whole retry story.