Overview
Theretry middleware automatically retries failed requests with configurable backoff strategies, handling transient failures gracefully.
Use it when you need:
- Handle temporary network issues
- Retry on specific error codes
- Implement exponential backoff
Installation
Quick Start
Configuration
Options
| Option | Type | Default | Description |
|---|---|---|---|
MaxRetries | int | 3 | Maximum retry attempts |
Delay | time.Duration | 100ms | Initial delay |
MaxDelay | time.Duration | 10s | Maximum delay |
Multiplier | float64 | 2.0 | Backoff multiplier |
RetryOn | []int | [500-599] | Status codes to retry |
RetryIf | func(*mizu.Ctx, error) bool | - | Custom retry condition |
Examples
Basic Retry
With Backoff
Specific Status Codes
Custom Condition
Constant Delay
API Reference
Functions
Backoff Calculation
- Attempt 1: 100ms
- Attempt 2: 200ms
- Attempt 3: 400ms
Technical Details
Implementation Architecture
The retry middleware uses a customretryResponseWriter wrapper that intercepts response status codes to determine if a retry should occur. Key implementation details:
- Response Writer Wrapping: Each retry attempt wraps the response writer to capture the status code without committing the response until success or max retries reached
- Exponential Backoff Algorithm: Delay calculation follows the formula:
delay = min(initialDelay * (multiplier ^ attempt), maxDelay) - Retry Decision Logic: The
RetryIffunction receives the context, error, and current attempt number to make intelligent retry decisions - State Management: The middleware tracks attempt count, last error, and current delay across retry iterations
Default Behavior
When usingNew() without options, the middleware:
- Retries up to 3 times (4 total attempts including initial)
- Starts with 100ms delay
- Uses 2.0x multiplier for exponential backoff
- Caps maximum delay at 1 second
- Retries on any error or 5xx HTTP status codes
Helper Functions
The package provides several helper functions for common retry patterns:RetryOn(codes ...int): Creates a RetryIf function that retries only on specific HTTP status codesRetryOnError(): Creates a RetryIf function that retries only when an error is returnedNoRetry(): Creates a RetryIf function that disables retries (useful for testing)
Performance Considerations
- The middleware sleeps between retries using
time.Sleep, blocking the goroutine - Response writer wrapping adds minimal overhead
- Status code capture happens in memory without additional allocations
- The
OnRetrycallback allows for logging and metrics without impacting retry logic
Best Practices
- Use exponential backoff to prevent thundering herd
- Set reasonable max retries (3-5)
- Only retry idempotent operations
- Add jitter for distributed systems
- Log retry attempts for debugging
Testing
Test Coverage
The retry middleware includes comprehensive test cases covering various scenarios:| Test Case | Description | Expected Behavior |
|---|---|---|
TestNew | Basic retry with default options | Retries up to 3 times on errors, succeeds on 3rd attempt |
TestWithOptions_MaxRetries | Custom max retries configuration | Respects MaxRetries setting (1 initial + 2 retries = 3 attempts) |
TestWithOptions_OnRetry | OnRetry callback invocation | OnRetry called before each retry attempt (not on initial attempt) |
TestWithOptions_NoRetryNeeded | Successful request on first attempt | No retries when request succeeds immediately |
TestWithOptions_CustomRetryIf | Custom retry condition logic | Custom RetryIf function controls retry behavior independently of MaxRetries |
TestRetryOn | RetryOn helper for specific status codes | Retries only on specified status codes (500, 502, 503) |
TestRetryOnError | RetryOnError helper function | Retries only when error is present, not on status codes |
TestNoRetry | NoRetry helper function | Never retries regardless of error or status code |
TestWithOptions_ExponentialBackoff | Exponential backoff timing | Delays increase exponentially between retry attempts |
Related Middlewares
- circuitbreaker - Circuit breaker
- timeout - Request timeout
- idempotency - Idempotency keys