Skip to content

Retry Delays

Retry delays determine how long to wait between retry attempts. Choosing the right strategy is crucial for balancing quick recovery with preventing service overload.

Quick Start: Common Retry Patterns

Web API Calls (Most Common)

csharp
// Recommended for external API calls
context.UseExponentialBackoffDelay(
    baseDelay: TimeSpan.FromSeconds(1),
    multiplier: 2.0,
    maxDelay: TimeSpan.FromMinutes(1));

Why this pattern:

  • Exponential backoff gives services time to recover
  • Prevents thundering herd problems
  • Balanced for typical API rate limits

Database Operations

csharp
// Recommended for database retry scenarios
context.UseLinearBackoffDelay(
    baseDelay: TimeSpan.FromMilliseconds(100),
    increment: TimeSpan.FromMilliseconds(200),  // Required - adds 200ms per retry
    maxDelay: TimeSpan.FromSeconds(5));

Why this pattern:

  • Linear growth is predictable for database connection pools
  • Shorter delays work well for transient lock contention
  • Conservative max delay prevents long-running transactions

File Processing

csharp
// Recommended for file system operations
context.UseFixedDelay(TimeSpan.FromSeconds(2));

Why this pattern:

  • File system recovery is typically immediate
  • Fixed delay provides predictable behavior
  • Simple and effective for I/O operations

Decision Flow for Choosing Retry Strategy

mermaid
flowchart TD
    A[What type of operation?] --> B{External Service?}
    B -->|Yes| C[Use Exponential Backoff]
    B -->|No| D{Database Operation?}
    D -->|Yes| E[Use Linear Backoff]
    D -->|No| F{File System?}
    F -->|Yes| G[Use Fixed Delay]
    F -->|No| H[Use Exponential Backoff<br>Default choice]
    
    C --> I[Configure base delay: 1s<br>Configure multiplier: 2.0<br>Configure max delay: 1m]
    E --> J[Configure base delay: 100ms<br>Configure increment: 200ms<br>Configure max delay: 5s]
    G --> K[Configure delay: 2s]
    H --> I
    
    style A fill:#e1f5fe
    style C fill:#e8f5e9
    style E fill:#e8f5e9
    style G fill:#e8f5e9
    style I fill:#fff3e0
    style J fill:#f3e5f5
    style K fill:#f3e5f5

Basic Implementation

Basic Pipeline with Retry Delays

csharp
using NPipeline;
using NPipeline.Pipeline;

public sealed class RetryQuickstartPipeline : IPipelineDefinition
{
    public void Define(PipelineBuilder builder, PipelineContext context)
    {
        // Configure retry delay strategy based on operation type
        context.UseExponentialBackoffDelay(
            baseDelay: TimeSpan.FromSeconds(1),
            multiplier: 2.0,
            maxDelay: TimeSpan.FromMinutes(1));

        var source = builder.AddSource<ApiSource, ApiResponse>("api-source");
        var transform = builder.AddTransform<DataTransform, ApiResponse, ProcessedData>("transform");
        var sink = builder.AddSink<DataSink, ProcessedData>("sink");

        builder.Connect(source, transform);
        builder.Connect(transform, sink);

        // Configure retry options
        builder.WithRetryOptions(new PipelineRetryOptions(
            MaxItemRetries: 3,
            MaxNodeRestartAttempts: 2,
            MaxSequentialNodeAttempts: 5
        ));
    }
}

Per-Node Retry Configuration

csharp
public void Define(PipelineBuilder builder, PipelineContext context)
{
    var source = builder.AddSource<DataSource, string>("source");
    
    // Fast retries for in-memory operations
    context.UseFixedDelay(TimeSpan.FromMilliseconds(50));
    var memoryTransform = builder.AddTransform<MemoryTransform, string, string>("memory-ops");
    
    // Slower retries for external API calls
    context.UseExponentialBackoffDelay(
        baseDelay: TimeSpan.FromSeconds(1),
        multiplier: 2.0,
        maxDelay: TimeSpan.FromMinutes(1));
    var apiTransform = builder.AddTransform<ApiTransform, string, string>("api-ops");
    
    // Default retries for other operations
    var sink = builder.AddSink<DataSink, string>("sink");

    builder.Connect(source, memoryTransform);
    builder.Connect(memoryTransform, apiTransform);
    builder.Connect(apiTransform, sink);
}

Available Strategies

Basic Strategies

StrategyPatternUse CaseLink
Exponential BackoffDelays grow exponentially (1s, 2s, 4s, 8s...)External APIs, distributed systemsLearn more
Linear BackoffDelays increase linearly (100ms, 300ms, 500ms...)Database operations, lock contentionLearn more
Fixed DelaySame delay each time (2s, 2s, 2s...)File system, simple scenarios, testingLearn more

Advanced Strategies

Key Concepts

Jitter

Add randomization to prevent synchronized retries:

csharp
context.UseExponentialBackoffDelay(
    baseDelay: TimeSpan.FromSeconds(1),
    multiplier: 2.0,
    maxDelay: TimeSpan.FromMinutes(1),
    jitterStrategy: JitterStrategies.FullJitter()); // Add jitter

Why: Without jitter, multiple clients retry at the same time, overwhelming the service ("thundering herd").

Jitter Options:

  • NoJitter() - Exact delays (use for testing only)
  • FullJitter() - Random 0 to calculated delay
  • EqualJitter() - Random between half and full delay
  • DecorrelatedJitter() - Adapts to system load

Retry Cap (maxDelay)

Always set a maximum delay to prevent indefinitely long waits:

csharp
context.UseExponentialBackoffDelay(
    baseDelay: TimeSpan.FromSeconds(1),
    multiplier: 2.0,
    maxDelay: TimeSpan.FromMinutes(1)); // Don't wait longer than 1 minute

Topics

Guides

Advanced

Best Practices

  1. Always add jitter - Prevents thundering herd in distributed systems
  2. Set reasonable caps - Don't wait longer than 1-5 minutes
  3. Start conservative - Begin with shorter delays, increase if needed
  4. Use fixed delays in tests - Ensures deterministic timing
  5. Monitor metrics - Track actual retry patterns in production
  6. Match strategy to domain - APIs ≠ Databases ≠ Files
  7. Document decisions - Explain why you chose specific settings

Next Steps

  • Choose a strategy based on your use case (API? Database? Files?)
  • Read the dedicated guide for your chosen strategy
  • Test retry behavior with Testing Retries

Released under the MIT License.