Version v1.0 · dotnet
Retry Policy
Retry eligibility, fixed-delay vs backoff behavior, and failure lifecycle.
Retry Policy
When a job throws, DurableStack evaluates retry eligibility using the current attempt and MaxAttempts, then schedules the next try with either fixed delay or backoff.
Retry rule
- Retry when
Attempt < MaxAttempts. - Reschedule for
UtcNow + calculated delay. - Mark terminal
failedwhen max attempts is reached.
MaxAttempts includes the initial attempt. Example: MaxAttempts = 3 allows one initial run + up to two retries.
Retry behavior modes
DurableStack supports two retry modes:
FixedDelay(default): every retry uses the same base delay.Backoff: each retry delay grows exponentially from the base delay (baseDelay * 2^(Attempt - 1)).
Attempt is the attempt that just failed. So with backoff and baseDelay = 5s:
- after attempt 1 fails:
5s - after attempt 2 fails:
10s - after attempt 3 fails:
20s
Where retry settings come from
Retry mode and initial delay can be set per job via [DurableJob], and global limits/tuning come from AddDurableStack options.
Per-job (attribute)
using DurableStack.Core.Models;
using DurableStack.Hosting.DependencyInjection;
[DurableJob(
Name = "send-digest-email",
MaxAttempts = 5,
RetryBehavior = RetryBehavior.Backoff,
RetryInitialDelaySeconds = 10)]
public sealed class SendDigestEmailJob : IDurableJob
{
public Task ExecuteAsync(JobContext context, CancellationToken cancellationToken = default)
{
return Task.CompletedTask;
}
}
RetryBehaviordefault:FixedDelayRetryInitialDelaySecondsdefault: unset (0on attribute), which falls back to globaloptions.RetryDelay
Global runtime options
builder.Services.AddDurableStack(options =>
{
options.RetryDelay = TimeSpan.FromSeconds(5); // Default base delay when per-job initial delay is not set.
options.RetryMaxDelay = TimeSpan.FromHours(1); // Upper cap applied to computed retry delay.
options.RetryJitterEnabled = false; // Enables random jitter when true.
options.RetryJitterRatio = 0.2; // +/- jitter ratio (0 to 1) when jitter is enabled.
});
Delay calculation order
- Start with base delay:
- per-job
RetryInitialDelaySecondsif set and > 0 - otherwise global
options.RetryDelay
- per-job
- Apply behavior:
FixedDelay: keep base delayBackoff: exponential growth per failed attempt
- Apply jitter if enabled
- Clamp to
options.RetryMaxDelayif exceeded
Status progression
pending->leased->succeededpending->leased->pending(retry)pending->leased->failed(terminal)
Guidance
- Use
FixedDelayfor predictable retry cadence. - Use
Backofffor transient dependency failures (API throttling, brief outages). - Keep job handlers idempotent so retries are safe.
- Keep
MaxAttemptslower for non-idempotent side effects. - Monitor retry and failure trends in observability dashboards.