Skip to main content
Transient failures happen. Retry strategies handle them gracefully with exponential backoff and jitter.

Basic Usage

from splinter.control import RetryStrategy, RetryConfig

strategy = RetryStrategy(RetryConfig(
    max_attempts=3,
    initial_delay=1.0,
    max_delay=30.0,
    backoff_multiplier=2.0,
))

# Retry automatically
result = await strategy.execute(flaky_function, arg1, arg2)

Retry Timing

With default config:
Attempt 1: Immediate
Attempt 2: Wait 1s
Attempt 3: Wait 2s
Attempt 4: Wait 4s (capped at max_delay)

Retry Modes

from splinter.control import RetryMode

# Basic: Retry on any exception
RetryConfig(mode=RetryMode.BASIC)

# Selective: Only retry specific exceptions
RetryConfig(
    mode=RetryMode.SELECTIVE,
    retry_on=[ConnectionError, TimeoutError],
)

# Fail-closed: Stop on first failure (for critical operations)
RetryConfig(mode=RetryMode.FAIL_CLOSED)

Jitter

Add randomness to prevent thundering herd:
RetryConfig(
    initial_delay=1.0,
    jitter=0.5,  # ±0.5s random
)
# Delay will be 0.5s to 1.5s

Custom Retry Conditions

def should_retry(exception, attempt):
    # Don't retry client errors
    if isinstance(exception, ClientError):
        return False
    # Retry server errors up to 5 times
    if isinstance(exception, ServerError):
        return attempt < 5
    return True

strategy = RetryStrategy(RetryConfig(
    retry_condition=should_retry,
))

Callbacks

def on_retry(attempt, exception, delay):
    print(f"Attempt {attempt} failed: {exception}")
    print(f"Retrying in {delay:.1f}s")

strategy = RetryStrategy(RetryConfig(
    max_attempts=3,
    on_retry=on_retry,
))

Circuit Breaker Integration

Combine with circuit breakers:
from splinter.control import RetryStrategy, CircuitBreaker

breaker = CircuitBreaker(breaker_id="api", failure_threshold=5)

async def call_with_protection():
    breaker.check()  # Raises if circuit open
    try:
        result = await strategy.execute(api_call)
        breaker.record_success()
        return result
    except Exception as e:
        breaker.record_failure()
        raise

Best Practices

Immediate retries can overwhelm failing services.
3-5 is usually enough. More than that, the service is probably down.
Prevents all clients from retrying at the same time.
400 errors won’t succeed on retry. Only retry 5xx and network errors.