docs/extensibility/index.md
This article explains how to extend Polly with new resilience strategies. Polly identifies two types of resilience strategies:
This guide will help you create a new illustrative resilience strategy for each type.
Regardless of whether the strategy is reactive or proactive, every new resilience strategy should include the following components:
ResilienceStrategyResilienceStrategyOptions.ResiliencePipelineBuilder or ResiliencePipelineBuilder<T> to register the strategy into the pipeline.The strategy options contain properties of following types:
int, bool, TimeSpan, etc.This diagram depicts how the built-in types (hexagon shaped) interact with custom built types (rectangle shaped):
flowchart
options[XYZStrategyOptions]
builder[XYZResilienceStrategyBuilderExtensions]
strategy[XYZResilienceStrategy]
args[XYZEventArguments]
telemetry{{ResilienceStrategyTelemetry}}
pipeline{{ResiliencePipeline}}
options -- is passed to AddXYZ --> builder
builder -- registers a strategy --> pipeline
options -- configures behavior --> strategy
pipeline -- calls the execution --> strategy
strategy -- creates for events --> args
strategy -- uses for reporting --> telemetry
%% a workaround to add note (currently only sequence diagram supports notes)
%% https://github.com/mermaid-js/mermaid/issues/821
args -.- note(The strategy calls
the OnXYZ delegate of
the options with this object.)
Individual resilience strategies make use of several delegate types:
Recommended signatures for these delegates are:
Func<Args<TResult>, ValueTask<bool>> (Reactive)Func<Args<TResult>, ValueTask> (Reactive)Func<Args, ValueTask> (Proactive)Func<Args<TResult>, ValueTask<TValue>> (Reactive)Func<Args, ValueTask<TValue>> (Proactive)These delegates accept either Args or Args<TResult> arguments, which encapsulate event information. Note that all these delegates are asynchronous and return a ValueTask. Learn more about arguments in the sections below.
[!NOTE] When setting up delegates, consider using the
ResilienceContext.ContinueOnCapturedContextproperty if your user code interacts with a synchronization context (such as in asynchronous UI applications like Windows Forms or WPF).
Below are some examples illustrating the usage of these delegates:
<!-- snippet: delegate-usage -->new ResiliencePipelineBuilder()
.AddRetry(new RetryStrategyOptions
{
// Non-Generic predicate for multiple result types
ShouldHandle = args => args.Outcome switch
{
{ Exception: InvalidOperationException } => PredicateResult.True(),
{ Result: string result } when result == "Failure" => PredicateResult.True(),
{ Result: int result } when result == -1 => PredicateResult.True(),
_ => PredicateResult.False()
},
})
.Build();
new ResiliencePipelineBuilder<string>()
.AddRetry(new RetryStrategyOptions<string>
{
// Generic predicate for a single result type
ShouldHandle = args => args.Outcome switch
{
{ Exception: InvalidOperationException } => PredicateResult.True(),
{ Result: { } result } when result == "Failure" => PredicateResult.True(),
_ => PredicateResult.False()
},
})
.Build();
Arguments are used by individual delegate types to flow information to the consumer. Arguments should always have an Arguments suffix and include a Context property. Using arguments boosts the extensibility and maintainability of the API, as adding new members becomes a non-breaking change. For proactive strategies, the arguments structure might resemble the following:
// Structs for arguments encapsulate details about specific events within the resilience strategy.
// Relevant properties to the event can be exposed. In this event, the actual execution time and the exceeded threshold are included.
public readonly struct OnThresholdExceededArguments
{
public OnThresholdExceededArguments(ResilienceContext context, TimeSpan threshold, TimeSpan duration)
{
Context = context;
Threshold = threshold;
Duration = duration;
}
public TimeSpan Threshold { get; }
public TimeSpan Duration { get; }
// As per convention, all arguments should provide a "Context" property.
public ResilienceContext Context { get; }
}
To find out more details about implementing a strategy, follow the links below: