-
Notifications
You must be signed in to change notification settings - Fork 1
Hedging
Marco Breveglieri edited this page Jul 20, 2026
·
1 revision
The Hedging pattern launches additional parallel attempts when the primary one is too slow or fails, returning the first attempt that succeeds. It trades extra work for lower tail latency.
- Reducing tail latency for calls to replicated or redundant services
- Flaky endpoints where an occasional slow or failed call shouldn't block the whole request
- Operations that are safe to run more than once at the same time (idempotent)
- Non-idempotent operations (e.g. anything that creates a resource, charges a payment, or has other side effects) - losing attempts keep running in the background and can still complete
- Calls to a single, non-replicated backend where extra parallel attempts just add load without improving the odds of success
- Expensive operations where launching multiple attempts in parallel is not acceptable from a cost or resource standpoint
uses Murphy.Policy.Hedging;
var
Policy: IHedgingPolicy;
begin
Policy := THedgingBuilder
.Handle(ENetworkError)
.MaxAttempts(2)
.Delay(TTimeSpan.FromMilliseconds(500))
.Build;
Policy.Execute(procedure begin CallReplicatedService; end);
end;procedure FetchFromReplica;
var
Policy: IHedgingPolicy;
begin
Policy := THedgingBuilder
.Handle(Exception)
.MaxAttempts(1) // One extra attempt
.Delay(TTimeSpan.FromMilliseconds(300)) // Hedge if slower than 300ms
.Build;
Policy.Execute(
procedure
begin
Result := CallAnyReplica;
end);
end;var Policy: IHedgingPolicy;
begin
Policy := THedgingBuilder
.Handle(ENetworkError)
.MaxAttempts(3)
.Delay(TTimeSpan.FromMilliseconds(200))
.OnHedging(procedure(Context: THedgingContext)
begin
WriteLn(Format('Launching hedged attempt #%d', [Context.AttemptNumber]));
end)
.Build;
Policy.Execute(procedure begin CallReplicatedService; end);
end;var Policy: IHedgingPolicy;
begin
Policy := THedgingBuilder.Handle(ENetworkError).MaxAttempts(2).Build;
try
Policy.Execute(procedure begin CallReplicatedService; end);
except
on E: ENetworkError do
WriteLn('All hedged attempts failed: ' + E.Message);
end;
end;- Only hedge idempotent actions - losing attempts are abandoned but keep running in the background, so side effects can still happen
- Set the delay based on expected latency - hedge too early and you waste resources on every call; too late and tail latency isn't improved
-
Cap
MaxAttempts- each extra attempt multiplies load on the backend; negative values raiseEArgumentException -
Use
OnHedgingfor observability - track how often hedged attempts fire to tune the delay - Combine with Timeout - bound how long the winning attempt itself is allowed to take