Skip to content

[Feature request]: Resilience Execution #2494

@caigen

Description

@caigen

Is your feature request related to a specific problem? Or an existing feature?

Polly already supports 2 main core concepts:

  • Resilience Policy
  • Resilience Pipeline

What I want to is:

I used it somewhere but wanted to contribute it back to Polly as I think it should be general and after it is added in polly, user can create resilience business logic easily & quickly. It can also be used for non-http related resilience.

Sample usage:

        // 1. Config Hedging & Timeout
        ResiliencePipelineBuilder<HttpResponseMessage> builder =
            new ResiliencePipelineBuilder<HttpResponseMessage>();
        builder = builder.AddHedging(
            new Polly.Hedging.HedgingStrategyOptions<HttpResponseMessage>
            {
                Delay = TimeSpan.FromSeconds(2),
                MaxHedgedAttempts = 1,
                ShouldHandle = async args =>
                {
                    return await Task.FromResult(args.Outcome.Result?.IsSuccessStatusCode ?? true);
                },
            });
        builder.AddTimeout(TimeSpan.FromSeconds(25));

        // 2. Build pipeline
        ResiliencePipeline<HttpResponseMessage> pipeline = builder.Build();

        // 3. Config ResilienceInvoker with multiple HttpClients
        FakeHttpClient fakeHttpClientA = new FakeHttpClient("A", 20);
        FakeHttpClient fakeHttpClientB = new FakeHttpClient("B", 5);

        // 4. runtime
        using HttpRequestMessage httpRequestMessage = new HttpRequestMessage();
        CancellationToken cancellationToken = new CancellationToken(false);

        // Invokers per request or we may have thread safety issue
        ResilienceInvoker<HttpResponseMessage, HttpRequestMessage> resilienceInvoker = new ResilienceInvoker<HttpResponseMessage, HttpRequestMessage>(
            pipeline,

            // Create one composite invoker internally
            new List<IInvoker<HttpResponseMessage, HttpRequestMessage>>
            {
                // Add multiple HttpClient here
                fakeHttpClientA,
                fakeHttpClientB
            });
        HttpResponseMessage httpResponseMessage = await resilienceInvoker.ExecuteAsync(httpRequestMessage, cancellationToken);
        Assert.Equal(HttpStatusCode.OK, httpResponseMessage.StatusCode);
        Assert.True(fakeHttpClientA.CalledNumber == 1 || fakeHttpClientB.CalledNumber == 1);

Describe the solution you'd like

/// <summary>
/// IInvoker interface: work together with Polly ResiliencePipeline as callback
/// See: https://www.pollydocs.org/pipelines/index.html .
/// </summary>
/// <typeparam name="TResult">The type of the result.</typeparam>
/// <typeparam name="TInput">The type of the input.</typeparam>
public interface IInvoker
    <TResult, TInput>
{
    /// <summary>
    /// Execute the request.
    /// </summary>
    /// <param name="request">The request.</param>
    /// <param name="cancellationToken">The cancellationToken.</param>
    /// <returns>The result.</returns>
    Task<TResult> ExecuteAsync(TInput request, CancellationToken cancellationToken);
}
classDiagram
    IInvoker <|-- CompositeInvoker
    IInvoker <|-- ResilienceInvoker
    class IInvoker{
      -//Execution abstraction
      -ExecuteAsync()
    }
    class CompositeInvoker{
      -IList _invokers
      +ExecuteAsync()
    }
    class ResilienceInvoker{
      +ResiliencePipeline _resiliencePipeline
      +CompositeInvoker _compositeInvoker
      +ExecuteAsync()
    }

Image

Additional context

IInvoker could be public.
CompositeInvoker could reuse current Composite infra in Polly Core.

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions