Skip to main content

Hedging Strategy

The hedging reactive resilience strategy enables the re-execution of callbacks if the previous execution takes too long. This approach can boost overall system responsiveness at the cost of increased resource utilization.
Do not start any background work when executing actions using the hedging strategy. This strategy can spawn multiple parallel tasks, potentially starting multiple background tasks.

When to Use Hedging

Use the hedging strategy when:
  • Low latency is critical and you can afford extra resource usage
  • Dealing with unpredictable response times from services
  • You want to hedge against slow responses (tail latency)
  • Some redundancy in operations is acceptable
  • The operation is idempotent (can be safely executed multiple times)
If low latency is not critical, consider using the retry strategy instead, which is more resource-efficient.

Installation

Hedging Modes

The hedging strategy supports multiple concurrency modes:

Latency Mode

Delays between hedged attempts. Default behavior with configurable delay.

Fallback Mode

Only one execution at a time. New attempt starts only after previous fails.

Parallel Mode

All attempts execute simultaneously. Fastest wins.

Dynamic Mode

Behavior changes based on runtime conditions using DelayGenerator.

Usage

Basic Hedging (Latency Mode)

Custom Hedging Configuration

Hedging with Events

Parallel Mode (Zero Delay)

Parallel mode consumes the most resources. Use only when absolutely necessary for critical low-latency operations.

Fallback Mode (Negative Delay)

Dynamic Mode

Custom Action Generator

Configuration Options

Predicate
Defines which results and/or exceptions should trigger hedging.
int
default:"1"
The maximum number of hedged actions to use, in addition to the original action.
TimeSpan
default:"2 seconds"
The waiting time before spawning a new hedged action:
  • Positive value: Latency mode (delay between attempts)
  • TimeSpan.Zero: Parallel mode (all attempts immediately)
  • Negative value: Fallback mode (sequential, one at a time)
Func<HedgingDelayGeneratorArguments, ValueTask<TimeSpan>>
default:"null"
Dynamically calculates the delay for each hedged attempt. If set, Delay is ignored.
Func<HedgingActionGeneratorArguments, Func<ValueTask<Outcome<TResult>>>>
default:"Returns original callback"
Generates the action to execute for each hedged attempt. Can return a completely different action.
Func<OnHedgingArguments, ValueTask>
default:"null"
Invoked before the strategy performs each hedged action.

Best Practices

Hedging executes the same operation multiple times. Ensure your operation is idempotent (safe to execute multiple times without side effects).
Begin with latency mode (positive delay) and tune the delay based on your P95/P99 latency metrics. Only move to parallel mode if necessary.
More attempts increase resource usage. Start with 1-2 hedged attempts and increase only if needed.
Ensure hedged actions properly respect cancellation tokens so they can be cancelled when a faster attempt succeeds.
Track CPU, memory, and network usage when using hedging, especially in parallel mode.
Hedging increases resource usage and can multiply costs for paid APIs. Use judiciously.

Examples

HTTP Request with Hedging

Multi-Endpoint Hedging

Database Query with Hedging

Adaptive Hedging

  • Retry: Executes attempts sequentially. Waits for one to fail before trying again.
  • Hedging: Can execute attempts concurrently. Doesn’t wait for failure, starts new attempts proactively when things are slow.
Hedging is for reducing latency; retry is for overcoming failures.
Use parallel mode (Delay = TimeSpan.Zero) only when:
  • Latency is absolutely critical (e.g., real-time trading, gaming)
  • You can afford the resource cost
  • The operation is lightweight
  • You’ve measured that latency mode isn’t sufficient
When the fastest attempt succeeds, Polly cancels all other pending attempts. This is why it’s crucial that your operations respect the cancellation token.
Yes! Use ActionGenerator to create different actions for each attempt. This is useful for:
  • Trying different service replicas
  • Falling back to cached data
  • Using alternative APIs
Start with your P95 or P99 latency. If 95% of requests complete in 500ms, set delay to 500ms. Tune based on observed performance and resource usage.