Code Monkey home page Code Monkey logo

app-vnext / polly Goto Github PK

View Code? Open in Web Editor NEW
13.2K 354.0 1.2K 39.38 MB

Polly is a .NET resilience and transient-fault-handling library that allows developers to express policies such as Retry, Circuit Breaker, Timeout, Bulkhead Isolation, and Fallback in a fluent and thread-safe manner. From version 6.0.1, Polly targets .NET Standard 1.1 and 2.0+.

Home Page: https://www.thepollyproject.org

License: BSD 3-Clause "New" or "Revised" License

C# 99.84% PowerShell 0.16% Batchfile 0.01%
circuit-breaker circuit-breaker-pattern resilience resiliency-patterns retry-strategies dotnet fault-handler transient-fault-handling

polly's Introduction

Polly

Polly is a .NET resilience and transient-fault-handling library that allows developers to express resilience strategies such as Retry, Circuit Breaker, Hedging, Timeout, Rate Limiter and Fallback in a fluent and thread-safe manner.

The .NET Foundation logo We are a member of the .NET Foundation!

Keep up to date with new feature announcements, tips & tricks, and other news through www.thepollyproject.org

Build status Code coverage OpenSSF Scorecard

Polly logo

Important

This documentation describes the new Polly v8 API. If you are using the v7 API, please refer to the previous version of the documentation.

NuGet Packages

Package Latest Version About
Polly.Core NuGet The core abstractions and built-in strategies.
Polly.Extensions NuGet Telemetry and dependency injection support.
Polly.RateLimiting NuGet Integration with System.Threading.RateLimiting APIs.
Polly.Testing NuGet Testing support for Polly libraries.
Polly NuGet This package contains the legacy API exposed by versions of the Polly library before version 8.

Documentation

This README aims to give a quick overview of some Polly features - including enough to get you started with any resilience strategy. For deeper detail on any resilience strategy, and many other aspects of Polly, be sure also to check out pollydocs.org.

Quick start

To use Polly, you must provide a callback and execute it using resilience pipeline. A resilience pipeline is a combination of one or more resilience strategies such as retry, timeout, and rate limiter. Polly uses builders to integrate these strategies into a pipeline.

To get started, first add the Polly.Core package to your project by running the following command:

dotnet add package Polly.Core

You can create a ResiliencePipeline using the ResiliencePipelineBuilder class as shown below:

// Create an instance of builder that exposes various extensions for adding resilience strategies
ResiliencePipeline pipeline = new ResiliencePipelineBuilder()
    .AddRetry(new RetryStrategyOptions()) // Add retry using the default options
    .AddTimeout(TimeSpan.FromSeconds(10)) // Add 10 seconds timeout
    .Build(); // Builds the resilience pipeline

// Execute the pipeline asynchronously
await pipeline.ExecuteAsync(static async token => { /* Your custom logic goes here */ }, cancellationToken);

Dependency injection

If you prefer to define resilience pipelines using IServiceCollection, you'll need to install the Polly.Extensions package:

dotnet add package Polly.Extensions

You can then define your resilience pipeline using the AddResiliencePipeline(...) extension method as shown:

var services = new ServiceCollection();

// Define a resilience pipeline with the name "my-pipeline"
services.AddResiliencePipeline("my-pipeline", builder =>
{
    builder
        .AddRetry(new RetryStrategyOptions())
        .AddTimeout(TimeSpan.FromSeconds(10));
});

// Build the service provider
var serviceProvider = services.BuildServiceProvider();

// Retrieve a ResiliencePipelineProvider that dynamically creates and caches the resilience pipelines
var pipelineProvider = serviceProvider.GetRequiredService<ResiliencePipelineProvider<string>>();

// Retrieve your resilience pipeline using the name it was registered with
ResiliencePipeline pipeline = pipelineProvider.GetPipeline("my-pipeline");

// Alternatively, you can use keyed services to retrieve the resilience pipeline
pipeline = serviceProvider.GetRequiredKeyedService<ResiliencePipeline>("my-pipeline");

// Execute the pipeline
await pipeline.ExecuteAsync(static async token =>
{
    // Your custom logic goes here
});

Resilience strategies

Polly provides a variety of resilience strategies. Alongside the comprehensive guides for each strategy, the wiki also includes an overview of the role each strategy plays in resilience engineering.

Polly categorizes resilience strategies into two main groups:

Reactive

These strategies handle specific exceptions that are thrown, or results that are returned, by the callbacks executed through the strategy.

Strategy Premise AKA Mitigation
Retry family Many faults are transient and may self-correct after a short delay. Maybe it's just a blip Allows configuring automatic retries.
Circuit-breaker family When a system is seriously struggling, failing fast is better than making users/callers wait.

Protecting a faulting system from overload can help it recover.
Stop doing it if it hurts

Give that system a break
Breaks the circuit (blocks executions) for a period, when faults exceed some pre-configured threshold.
Fallback Things will still fail - plan what you will do when that happens. Degrade gracefully Defines an alternative value to be returned (or action to be executed) on failure.
Hedging Things can be slow sometimes, plan what you will do when that happens. Hedge your bets Executes parallel actions when things are slow and waits for the fastest one.

Proactive

Unlike reactive strategies, proactive strategies do not focus on handling errors, but the callbacks might throw or return. They can make proactive decisions to cancel or reject the execution of callbacks.

Strategy Premise AKA Prevention
Timeout Beyond a certain wait, a success result is unlikely. Don't wait forever Guarantees the caller won't have to wait beyond the timeout.
Rate Limiter Limiting the rate a system handles requests is another way to control load.

This can apply to the way your system accepts incoming calls, and/or to the way you call downstream services.
Slow down a bit, will you? Constrains executions to not exceed a certain rate.

Visit resilience strategies docs to explore how to configure individual resilience strategies in more detail.

Retry

// Retry using the default options.
// See https://www.pollydocs.org/strategies/retry#defaults for defaults.
var optionsDefaults = new RetryStrategyOptions();

// For instant retries with no delay
var optionsNoDelay = new RetryStrategyOptions
{
    Delay = TimeSpan.Zero
};

// For advanced control over the retry behavior, including the number of attempts,
// delay between retries, and the types of exceptions to handle.
var optionsComplex = new RetryStrategyOptions
{
    ShouldHandle = new PredicateBuilder().Handle<SomeExceptionType>(),
    BackoffType = DelayBackoffType.Exponential,
    UseJitter = true,  // Adds a random factor to the delay
    MaxRetryAttempts = 4,
    Delay = TimeSpan.FromSeconds(3),
};

// To use a custom function to generate the delay for retries
var optionsDelayGenerator = new RetryStrategyOptions
{
    MaxRetryAttempts = 2,
    DelayGenerator = static args =>
    {
        var delay = args.AttemptNumber switch
        {
            0 => TimeSpan.Zero,
            1 => TimeSpan.FromSeconds(1),
            _ => TimeSpan.FromSeconds(5)
        };

        // This example uses a synchronous delay generator,
        // but the API also supports asynchronous implementations.
        return new ValueTask<TimeSpan?>(delay);
    }
};

// To extract the delay from the result object
var optionsExtractDelay = new RetryStrategyOptions<HttpResponseMessage>
{
    DelayGenerator = static args =>
    {
        if (args.Outcome.Result is HttpResponseMessage responseMessage &&
            TryGetDelay(responseMessage, out TimeSpan delay))
        {
            return new ValueTask<TimeSpan?>(delay);
        }

        // Returning null means the retry strategy will use its internal delay for this attempt.
        return new ValueTask<TimeSpan?>((TimeSpan?)null);
    }
};

// To get notifications when a retry is performed
var optionsOnRetry = new RetryStrategyOptions
{
    MaxRetryAttempts = 2,
    OnRetry = static args =>
    {
        Console.WriteLine("OnRetry, Attempt: {0}", args.AttemptNumber);

        // Event handlers can be asynchronous; here, we return an empty ValueTask.
        return default;
    }
};

// To keep retrying indefinitely or until success use int.MaxValue.
var optionsIndefiniteRetry = new RetryStrategyOptions
{
    MaxRetryAttempts = int.MaxValue,
};

// Add a retry strategy with a RetryStrategyOptions{<TResult>} instance to the pipeline
new ResiliencePipelineBuilder().AddRetry(optionsDefaults);
new ResiliencePipelineBuilder<HttpResponseMessage>().AddRetry(optionsExtractDelay);

If all retries fail, a retry strategy rethrows the final exception back to the calling code.

For more details, visit the retry strategy documentation.

Circuit Breaker

// Circuit breaker with default options.
// See https://www.pollydocs.org/strategies/circuit-breaker#defaults for defaults.
var optionsDefaults = new CircuitBreakerStrategyOptions();

// Circuit breaker with customized options:
// The circuit will break if more than 50% of actions result in handled exceptions,
// within any 10-second sampling duration, and at least 8 actions are processed.
var optionsComplex = new CircuitBreakerStrategyOptions
{
    FailureRatio = 0.5,
    SamplingDuration = TimeSpan.FromSeconds(10),
    MinimumThroughput = 8,
    BreakDuration = TimeSpan.FromSeconds(30),
    ShouldHandle = new PredicateBuilder().Handle<SomeExceptionType>()
};

// Circuit breaker using BreakDurationGenerator:
// The break duration is dynamically determined based on the properties of BreakDurationGeneratorArguments.
var optionsBreakDurationGenerator = new CircuitBreakerStrategyOptions
{
    FailureRatio = 0.5,
    SamplingDuration = TimeSpan.FromSeconds(10),
    MinimumThroughput = 8,
    BreakDurationGenerator = static args => new ValueTask<TimeSpan>(TimeSpan.FromMinutes(args.FailureCount)),
};

// Handle specific failed results for HttpResponseMessage:
var optionsShouldHandle = new CircuitBreakerStrategyOptions<HttpResponseMessage>
{
    ShouldHandle = new PredicateBuilder<HttpResponseMessage>()
        .Handle<SomeExceptionType>()
        .HandleResult(response => response.StatusCode == HttpStatusCode.InternalServerError)
};

// Monitor the circuit state, useful for health reporting:
var stateProvider = new CircuitBreakerStateProvider();
var optionsStateProvider = new CircuitBreakerStrategyOptions<HttpResponseMessage>
{
    StateProvider = stateProvider
};

var circuitState = stateProvider.CircuitState;

/*
CircuitState.Closed - Normal operation; actions are executed.
CircuitState.Open - Circuit is open; actions are blocked.
CircuitState.HalfOpen - Recovery state after break duration expires; actions are permitted.
CircuitState.Isolated - Circuit is manually held open; actions are blocked.
*/

// Manually control the Circuit Breaker state:
var manualControl = new CircuitBreakerManualControl();
var optionsManualControl = new CircuitBreakerStrategyOptions
{
    ManualControl = manualControl
};

// Manually isolate a circuit, e.g., to isolate a downstream service.
await manualControl.IsolateAsync();

// Manually close the circuit to allow actions to be executed again.
await manualControl.CloseAsync();

// Add a circuit breaker strategy with a CircuitBreakerStrategyOptions{<TResult>} instance to the pipeline
new ResiliencePipelineBuilder().AddCircuitBreaker(optionsDefaults);
new ResiliencePipelineBuilder<HttpResponseMessage>().AddCircuitBreaker(optionsStateProvider);

For more details, visit the circuit breaker strategy documentation.

Fallback

// A fallback/substitute value if an operation fails.
var optionsSubstitute = new FallbackStrategyOptions<UserAvatar>
{
    ShouldHandle = new PredicateBuilder<UserAvatar>()
        .Handle<SomeExceptionType>()
        .HandleResult(r => r is null),
    FallbackAction = static args => Outcome.FromResultAsValueTask(UserAvatar.Blank)
};

// Use a dynamically generated value if an operation fails.
var optionsFallbackAction = new FallbackStrategyOptions<UserAvatar>
{
    ShouldHandle = new PredicateBuilder<UserAvatar>()
        .Handle<SomeExceptionType>()
        .HandleResult(r => r is null),
    FallbackAction = static args =>
    {
        var avatar = UserAvatar.GetRandomAvatar();
        return Outcome.FromResultAsValueTask(avatar);
    }
};

// Use a default or dynamically generated value, and execute an additional action if the fallback is triggered.
var optionsOnFallback = new FallbackStrategyOptions<UserAvatar>
{
    ShouldHandle = new PredicateBuilder<UserAvatar>()
        .Handle<SomeExceptionType>()
        .HandleResult(r => r is null),
    FallbackAction = static args =>
    {
        var avatar = UserAvatar.GetRandomAvatar();
        return Outcome.FromResultAsValueTask(UserAvatar.Blank);
    },
    OnFallback = static args =>
    {
        // Add extra logic to be executed when the fallback is triggered, such as logging.
        return default; // Returns an empty ValueTask
    }
};

// Add a fallback strategy with a FallbackStrategyOptions<TResult> instance to the pipeline
new ResiliencePipelineBuilder<UserAvatar>().AddFallback(optionsOnFallback);

For more details, visit the fallback strategy documentation.

Hedging

// Hedging with default options.
// See https://www.pollydocs.org/strategies/hedging#defaults for defaults.
var optionsDefaults = new HedgingStrategyOptions<HttpResponseMessage>();

// A customized hedging strategy that retries up to 3 times if the execution
// takes longer than 1 second or if it fails due to an exception or returns an HTTP 500 Internal Server Error.
var optionsComplex = new HedgingStrategyOptions<HttpResponseMessage>
{
    ShouldHandle = new PredicateBuilder<HttpResponseMessage>()
        .Handle<SomeExceptionType>()
        .HandleResult(response => response.StatusCode == HttpStatusCode.InternalServerError),
    MaxHedgedAttempts = 3,
    Delay = TimeSpan.FromSeconds(1),
    ActionGenerator = static args =>
    {
        Console.WriteLine("Preparing to execute hedged action.");

        // Return a delegate function to invoke the original action with the action context.
        // Optionally, you can also create a completely new action to be executed.
        return () => args.Callback(args.ActionContext);
    }
};

// Subscribe to hedging events.
var optionsOnHedging = new HedgingStrategyOptions<HttpResponseMessage>
{
    OnHedging = static args =>
    {
        Console.WriteLine($"OnHedging: Attempt number {args.AttemptNumber}");
        return default;
    }
};

// Add a hedging strategy with a HedgingStrategyOptions<TResult> instance to the pipeline
new ResiliencePipelineBuilder<HttpResponseMessage>().AddHedging(optionsDefaults);

If all hedged attempts fail, the hedging strategy will either re-throw the original exception or return the original failed result to the caller.

For more details, visit the hedging strategy documentation.

Timeout

The timeout resilience strategy assumes delegates you execute support co-operative cancellation. You must use Execute/Async(...) overloads taking a CancellationToken, and the executed delegate must honor that CancellationToken.

// To add a timeout with a custom TimeSpan duration
new ResiliencePipelineBuilder().AddTimeout(TimeSpan.FromSeconds(3));

// Timeout using the default options.
// See https://www.pollydocs.org/strategies/timeout#defaults for defaults.
var optionsDefaults = new TimeoutStrategyOptions();

// To add a timeout using a custom timeout generator function
var optionsTimeoutGenerator = new TimeoutStrategyOptions
{
    TimeoutGenerator = static args =>
    {
        // Note: the timeout generator supports asynchronous operations
        return new ValueTask<TimeSpan>(TimeSpan.FromSeconds(123));
    }
};

// To add a timeout and listen for timeout events
var optionsOnTimeout = new TimeoutStrategyOptions
{
    TimeoutGenerator = static args =>
    {
        // Note: the timeout generator supports asynchronous operations
        return new ValueTask<TimeSpan>(TimeSpan.FromSeconds(123));
    },
    OnTimeout = static args =>
    {
        Console.WriteLine($"{args.Context.OperationKey}: Execution timed out after {args.Timeout.TotalSeconds} seconds.");
        return default;
    }
};

// Add a timeout strategy with a TimeoutStrategyOptions instance to the pipeline
new ResiliencePipelineBuilder().AddTimeout(optionsDefaults);

Timeout strategies throw TimeoutRejectedException when a timeout occurs.

For more details, visit the timeout strategy documentation.

Rate Limiter

// Add rate limiter with default options.
// See https://www.pollydocs.org/strategies/rate-limiter#defaults for defaults.
new ResiliencePipelineBuilder()
    .AddRateLimiter(new RateLimiterStrategyOptions());

// Create a rate limiter to allow a maximum of 100 concurrent executions and a queue of 50.
new ResiliencePipelineBuilder()
    .AddConcurrencyLimiter(100, 50);

// Create a rate limiter that allows 100 executions per minute.
new ResiliencePipelineBuilder()
    .AddRateLimiter(new SlidingWindowRateLimiter(
        new SlidingWindowRateLimiterOptions
        {
            PermitLimit = 100,
            Window = TimeSpan.FromMinutes(1)
        }));

Rate limiter strategy throws RateLimiterRejectedException if execution is rejected.

For more details, visit the rate limiter strategy documentation.

Chaos engineering

Starting with version 8.3.0, Polly has integrated Simmy, a chaos engineering library, directly into its core. For more information, please refer to the dedicated chaos engineering documentation.

Next steps

To learn more about Polly, visit pollydocs.org.

Samples

  • Samples: Samples in this repository that serve as an introduction to Polly.
  • Polly-Samples: Contains practical examples for using various implementations of Polly. Please feel free to contribute to the Polly-Samples repository in order to assist others who are either learning Polly for the first time, or are seeking advanced examples and novel approaches provided by our generous community.
  • Microsoft's eShopOnContainers project: Sample project demonstrating a .NET Micro-services architecture and using Polly for resilience.

Sponsors

Thanks to the following companies for sponsoring the ongoing development of Polly.

AWS logo Microsoft logo

Help support this project by becoming a sponsor through GitHub Sponsors.

License

Licensed under the terms of the New BSD License

polly's People

Contributors

baranyaimate avatar dependabot[bot] avatar dreisenberger avatar freakazoid182 avatar geeknoid avatar ghuntley avatar gintsk avatar github-actions[bot] avatar iamdmitrij avatar ievangelist avatar joelhulen avatar kesmy avatar kristianhald avatar lakario avatar martincostello avatar martintmk avatar mauricedb avatar michael-wolfenden avatar moerwald avatar nedstoyanov avatar nelsonghezzi avatar peter-csala avatar polly-updater-bot[bot] avatar reisenberger avatar sensational-code avatar simoncropp avatar stevecote avatar vany0114 avatar yevhen avatar zombach avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

polly's Issues

WaitAndRetry action with a count.

I'd like to get an error count on the action when I use WaitAndRetry much like the standard Retry so I can avoid writing something like this.

Policy.Handle()
.Retry(3, (exception, retryCount) =>
{
if (retryCount < 3)
{
logger.Warn("SocialMedia.Checker", exception);
Thread.Sleep(TimeSpan.FromSeconds(3));
}
if (retryCount == 3)
{
logger.Error("SocialMedia.Checker", exception);
}
Thread.Sleep(TimeSpan.FromMinutes(1));
});

Policy ExecuteAsync method hangs if .Result is used.

Hey there, first of all thanks for the great work that you have been made

We created a execution policy solution based on Polly and we face following problem. When we call Task.Result the thread hangs. We made an investigation over the code and the conclusion is that the problem is in the implementation of Polly. We Fork the project and change the implementation of PoicyAsync.cs on line 45.
Original:

 await _asyncExceptionPolicy(async () => { result = await action().NotOnCapturedContext(); });

With this one:

 await _asyncExceptionPolicy(async () => { result = await action().NotOnCapturedContext(); }).NotOnCapturedContext();

And this fixed the issue for us.

Cheers,
Hacko

Feature Request: Add ability for Policies to react to return values, not just exceptions

Hi,

I would like to have the ability to retry method that does not throw exception, in my case I have to do some work with a COM component. In some condition the method I'm calling return null and null is a non valid result for me. I would like to have the ability to retry this method if the result is null.

Best regards, Max.

P.S. Thanks for this great library!

alternative naming for Execute method

As i read through the readme I liked the syntax and style of the fluent syntax. When i reached how to run a policy the method Execute felt somewhat jarring. Since we are dealing with policies Enact or Enforce might fit better.

Ex)

policy.Enforce(()=> MyCode());

Or

policy.Enact(() => MyCode());

Not a huge deal since someone could probably achieve this with extension methods in their code but I think it would bring the policy metaphor through to the end.

The default sleep delegate does not block in the PCL assembly

When using Polly in a PCL, the default value for SystemClock.Sleep does not block. The result is that any retries from RetryAndWait() will be fired in rapid succession.

I'm using the following replacement in my code, and it seems to be working:

SystemClock.Sleep = timespan => new ManualResetEvent(false).WaitOne(timespan);

Passing exception and retry count to execution (general: pass mutable data between onRetry and Execute)

Hi,

In policy execution, I need to access the retry number and the exception that was thrown.

I managed to do this only with class members, as in this console app:

class Program
{
    private static Exception mException;
    private static int mRetryCount;

    static void Main(string[] args)
    {
        var policy = Policy.Handle<DivideByZeroException>().Retry((exception, retryCount, context) =>
        {
            mException = exception;
            mRetryCount = retryCount;
        });

        policy.Execute(DoSomething);
    }

    private static void DoSomething()
    {
        Console.WriteLine("Try number {0}", mRetryCount);
        Console.WriteLine("Exception was {0}", mException);
        Console.WriteLine();

        int x = 0;
        var y = 2/x;
    }
}

However, is there a way to do this only with Polly, without class members?

Will the circuit breaker trip if enough minor transient errors happen? Should frequency of exceptions or interval between exceptions be a factor?

Hi,

The circuit breaker doesn't handle the scenario where we get a small amount of errors over an extended period of time. The circuit breaker state keeps just a simple count and breaks for a hard set amount of time once it's seen the set number of exceptions.

Say we're using Polly to wrap a call an external web service that errors out once an hour. After three hours we'll lock up hard, even though we probably don't want to break the circuit in this scenario.

Does it make sense to have some sort of expiration on when an exception happens so that their effect dampens over time?

Allow Handle to use function call without Exception generic type

Hi,

Handle expects an exception each time. This makes it difficult to have standard policy handlers using a decorator pattern across the system. This is because the exception to trap may be different based on the context, i.e. In one part of the system the exception may be System.TimeoutException, in another it may be a SqlException, but the Policy handling is the same.

Either allow injection of the Handle logic via DI with an interface, or allow Handle to take a function method that just returns a bool, thereby allowing in-line anonymous methods to do a similar job to DI

Thanks!

Thread Safe?

I don't see it is thread safe ?

I just wanted to know whether it is thread safe or not?

and how van i use it for thread safe with example can you explain?

Simple example

Hi.
I am trying to make a simple example for retry. But is not catching the exception. I try to send a new value in zero variable, but neither work. What is wrong with this code? Thx in advance.

static long zero = 0;
static void Main(string[] args)
{
try
{

            var policy = Policy
             .Handle<System.DivideByZeroException>()
             .Retry(3, (exception, retryCount, context) =>
             {
                 zero++;
             });

            var result = policy.Execute(
                () => DoSomething()
            );
        }
        catch(DivideByZeroException)
        {
            Console.WriteLine("No se porque estaria esto aqui");
        }
        catch(Exception ex)
        {
            Console.WriteLine( ex.TargetSite);
        }
         Console.ReadKey();

    }

    static long DoSomething()
    {
        long resultado = 1 / zero;
        return resultado;
    }

Looking for a new maintainer / home

Unfortunately due to new commitments, I am unable to continue to maintain this project. If anyone is interested in taking over please respond to this issue.

FEATURE: Fallback policy

As I understand it today, if I use Polly to setup a circuit breaker in my policy and that the circuit does break, I will receive a BrokenCircuitException. As a user of the framework, I need to handle this exception and write some code to specify how I want to react to this event. I would prefer to give to Polly that code and let it execute it if the circuit is broken. It would be better performance-wise, and much cleaner.

Policy
  .Handle<DivideByZeroException>()
  .CircuitBreaker(2, TimeSpan.FromMinutes(1))
  .WhenBroken(
  () => throw new BrokenCircuitException(); //Or another fallback method specific to my app.
)

Running async actions on captured synchronization context

Runnng Polly inside MS Orleans grain is not possible, since Orleans uses custom TaskScheduler and due to automatically added ConfigureAwait(false) action escapes it and runs on different thread, thus breaking single-threaded guarantee provided by Orleans.

Is that possible to add an overload for RetryAsync\WaitRetryAsync that will allow to control that behavior?

P.S. I'll be happy to send a PR but I have no idea what feature/project type my VS15 installation is missing, that I cannot load Polly.Shared projects. It tell me that The imported project "C:\Program Files (x86)\MSBuild\Microsoft\WindowsXaml\v14.0\8.1\Microsoft.Windows.UI.Xaml.CSharp.targets" was not found. Confirm that the path in the <Import> declaration is correct, and that the file exists on disk. C:\Program Files (x86)\MSBuild\Microsoft\WindowsXaml\v14.0\Microsoft.Windows.UI.Xaml.CSharp.targets 😟

Is that ExpressionDesigner that need to be installed?

Add ability to cancel retry and throw exception

Sometimes I want to have a WaitAndRetry policy handling an exception type that will work normally for certain situations but quickly bomb out in other situations, for example:

var policy = Policy.Handle<ThirdPartyHttpException>().WaitAndRetryAsync(1, i => TimeSpan.FromSeconds(2*i), async (exception, timespan) => {
    if (exception.StatusCode == 503) {
        Log("failed, trying again...");
    }
    if (exception.StatusCode == 404) {
        throw new ApiException("Not Found"); //this doesn't work
    }
});

Basically, I either want a safe way of throwing exceptions from the handler or a way to cancel all future retries so I can fail out quickly when I know something won't succeed. There isn't a good way to tell based on exception type. Is there an easy way to do this?

Pattern for CircuitBreaker? - can't get it to work

Hi,
I am trying to use the circuitbreaker but it never fires as I expect even though I believe I have followed the pattern correctly. Although it's a little unclear from the documentation, I think the use case is that Polly will throw the original exception raised until it hits the limit count for that exception, at which point it will throw a BrokenCircuitException until the timespan has expired.

I can't find any tests in the sourcecode to verify this - have these been migrated across from Michael??

Simple circuit breaker code:

try
{
var pol = Policy
.Handle<ArgumentNullException>()
.CircuitBreaker(3, TimeSpan.FromSeconds(60));

pol.Execute(() =>
{
throw new ArgumentNullException("");
});
}
catch (BrokenCircuitException ex)
{
throw new ServiceUnavailableException(ex);
}

My test:

Assert.That(() => handler.CauseBreakerException(), Throws.InstanceOf<ArgumentNullException>());
Assert.That(() => handler.CauseBreakerException(), Throws.InstanceOf<ArgumentNullException>());
Assert.That(() => handler.CauseBreakerException(), Throws.InstanceOf<ArgumentNullException>());
Assert.That(() => handler.CauseBreakerException(), Throws.InstanceOf<ServiceUnavailableException>());

The final step does not get a ServiceUnavailableException which means the BrokenCircuitException exception is never caught. The code will continually raise an ArgumentNullException exception each time.

Cannot combine ContextualPolicy and Policy; [DONE: document nesting Polly statements]

Hi,

I've just battled through a rather complex policy statement. I think it would help as an example on the readme and/or samples project.
Moreover I think I've found a gap in the API or rather something rather non-obvious that would be worth helping either via a new method/extension.

In particular we have a need to wrap Policy statements - a retryforever (that logs error) wrapping a retry and backoff (that logs warning). An extra complexity is that somethimes we want that behaviour and sometimes we want another policy. I know.

So our policy:

private Polly.Policy SetRetryPolicy(int retries, int retryWaitInMilliseconds, bool isFromApi)
{
    if (!isFromApi)
    {   
        return
            Polly
                .Policy
                .Handle<Exception>()
                .RetryForever(exception =>
                {
                    _log.ErrorFormat("An erros with Exception detail " + exception);
                })
                .Execute(() =>
                    Polly
                        .Policy
                        .Handle<Exception>()
                        .WaitAndRetry(
                            retries,
                            retryAttempt => TimeSpan.FromMilliseconds(retryWaitInMilliseconds*Math.Pow(2, retryAttempt)),
                            (exception, timeSpan) =>
                            {
                                _log.WarnFormat("An erros with Exception detail " + exception);
                            }));
    }
    return
        Polly
            .Policy
            .Handle<AggregateException>()
            .Retry(retryWaitInMilliseconds, (exception, i) =>
            {
                _connectionSingleton.Stop();
                _log.ErrorFormat("An erros with Exception detail " + exception);
            });
}

The issue I'd like to point attention to is I was passing to the WaitAndRetry method above the following:

(exception, timeSpan, *context*) => ...

.... this has the effect of creating a ContextualPolicy, whereas the second Policy was a Polly.Policy.

  • There is no way to combine a ContextualPolicy and Policy
  • It's very easy to miss this in amongst the various overloads.

I love how Polly works but the lack of examples covering wrapping policies really stymied me. Any help / guidance for others could help.

Ability to specify a zero retry or new method called NoRetry()

My use case is that I am using Polly not as a retry mechanism but instead as a catch exception by type and perform an action.

var policy = Policy
.Handle(ex => { errorCode = "not implemented"; return true; })
.Or(ex => { errorCode = "server_error"; return true; })
.NoRetry();
policy
.Execute(() =>
{
throw new ApplicationException("fun");
}

Share policy instace

Can I share a Policy instance between threads, or should I create a new instance each time I run a policy?

Ignore

Forgot my coffee this morning ...

Thanks for the library, my code is very clean even with complex retry logic. Thanks.

Circuit Breaking OnBreak/OnReset Actions

Has there been thought given to providing events to fire when the circuit is broken, and when the circuit is again open?

The use case I'm thinking of is when the application is consuming from a message queue we want to tear down the message queue connection so the work goes to other services, but we also want to wire back up to the queue once the circuit is again open.

I've done a fork and I have a crude example and I'll work on a pull request if the maintainers feel that this is something that would be of value to the project as a whole and not solely a scenario I'm concerned with.

But why?

Hello,

Could you please clarify why one would like to use Polly instead of handling exception in a mainstream fashion?
I'm asking this because it seems to me that while using Polly will reduce boilerplate, it will be more obscure to those who read the code.

Thanks!

RetryForever with Wait

It would be useful to be able to include a delay while waiting forever.

Currently I'm using int.MaxValue as a work around.

In a similar vein it would be handy to have the error count in the lambda so we can log on a decaying scale, I appreciate that this would eventually throw a Overflow Exception but just a hard cap at int.MaxValue would be fine.

Pass arbitrary data to Policy execution

I have a generic policy, like this:

        private static readonly Policy _basicRetryPolicy = Policy
                                        .Handle<Exception>()
                                        .WaitAndRetry(3,
                                        retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt + 3)),  //exponetial backoff, 2^4, 2^5 and 2^6 seconds between retry (16sec, 32sec and 64sec)
                                        (exception, timespan) =>
                                        {
                                            Logger.Info("Retry operation - wait :" + timespan.TotalSeconds.ToString());
                                        });

Now you can see I am writing to a log when the retry operation happens. However, I am using this same policy for many different Execute() functions. I would like to perhaps be able to pass some data, maybe just a string that says what call this is - so when the log is written it can accurately record which operation is retrying.

Is there a way to do this - if not, do you think it is a valuable addition to your library (perhaps as an optional parameter to the Execute() call - and then that parameter passed into the lambdas like timespan/retryattempt/exception is?

After final failure wrap and throw a new exception

Hi,

I'm doing something like this:

return await Policy
.Handle(ex => _strategy.IsTransient(ex))
.WaitAndRetryAsync(new[]
{
TimeSpan.FromMilliseconds(250),
TimeSpan.FromMilliseconds(500),
TimeSpan.FromMilliseconds(750)
}, (ex, retryCount) =>
{
retries = retries + 1;
//TODO: Log
})
.ExecuteAsync(() => _decoratedAsync.ExecuteAsync(query)).ConfigureAwait(false);

This is a generic handler where I inject the strategy and the code to be run. However in some cases I need the handler to catch a final (e.g.) "Service Slow" exception and then raise a Service Unavailable instead. As this is a generic handler, it's only applicable in a few cases so I don't really want to write a custom handler with a try - catch for this.

Can this be done in Polly? (maybe use the retry count?)

Feature request - public API for the policies list

It will be great if you could add a public API for the policies collection (the ones that are internal in PolicyBuilder) so it would be possible to cancel or reset a policy. Extremlly useful in integration tests when testing a class that uses the policy features. I want the ability to reset the policy after each test.

WaitAndRetryAsync(...) blocks threads with Thread.Sleep(), causes thread starvation

Aware @michael-wolfenden has said he wishes to step back (sorry to hear Michael; beautiful idiom Polly has created). Posting still a specific issue for ongoing Polly community - plus a question it raises poss feeds in to future directions for Polly.

Specific bug/issue: WaitAndRetryAsync(...) is not very async/await friendly, because the underlying implementation blocks with Thread.Sleep(Timespan). Blocking threads kind of against the grain of async/await?

Suggest move the RetryAndWaitAsync(...) implementation to something non-thread-blocking
like await Task.Delay(Timespan). Moving the RetryAndWaitAsync() implementation to await Task.Delay would also open up the possibility to solve #46 Add cancellation support (with Task.Delay overload taking CancellationToken).

Future directions: this prompted the question for me whether Polly should be kept as one library trying to support all of .NET3.5, .NET4, 4.5, PCL etc; whether it should be split; or when support for earlier .NET variants should be dropped. Obviously a plus for a library to work against various versions (as now). However, also a concern that supporting the older variants (/all in same library) might be holding back unleashing support for some of the .NET4.5+ features, such as those which would really make async/await work...?

Add GetResultOrThrow() method to PolicyResult<TResult>

It looks like there is an overwhelming amount of ceremony for a particular ExecuteAndCapture scenario.

What we currently do:

var policyResult = policy.ExecuteAndCapture(...);
if (policyResult.FinalException != null)
    throw policyResult.FinalException;
return policyResult.Result;

It would be nice to cover this common scenario in one shot:

return policy.ExecuteAndCapture(...).GetResultOrThrow();

Please consider to add GetResultOrThrow() method to PolicyResult class or maybe I just miss something and you can suggest a better approach.

continueOnCapturedContext API could be simplified

The initial continueOnCapturedContext API (#53) requires continueOnCapturedContext to be specified in two places, in Policy configuration and in delegate execution. For example:

Policy.Handle<Exception>.RetryForeverAsync(true).ExecuteAsync(action, true)

This leads to the possibility of writing inherently self-contradictory statements:

Policy.Handle<Exception>.RetryForeverAsync(false).ExecuteAsync(action, true);
// or
Policy.Handle<Exception>.RetryForeverAsync(true).ExecuteAsync(action, false); // Should callers expect this flows on the captured synchronization context or not?

While library users might be unlikely to directly write self-contradictory statements, the syntax could lead to missed user expectations, because of the way continueOnCapturedContext defaults to false (as recommended for async library code) when omitted.

For example, on a quick read of the below two statements, library users might intuitively expect that they will cause the action to execute continuing-on-captured-context. (Neither does, because of the implied false of the omitted parameter.)

Policy.Handle<Exception>.RetryForeverAsync().ExecuteAsync(action, true);
// or
Policy.Handle<Exception>.RetryForeverAsync(true).ExecuteAsync(action);

It would be nice if we could simplify the API to only require continueOnCapturedContext to be specified in one place. For example if:

Policy.Handle<Exception>.RetryForeverAsync().ExecuteAsync(action, true);

did completely control continueOnCapturedContext.

PR coming for this in a moment.

Policy .Handle<Exception> not absorbing the exception

I think I may be misunderstanding what the .Handle tag actually does for a policy. As Polly doesn't officially have a StackOverflow tag I thought I would link my issue from here.

Basically my issue is that in using Polly with Xamarin iOS it does not appear that my exception is actually being caught by the .Handle tag on my policy.

Am I misunderstanding how this is supposed to work?

Add Attempt count to PolicyResult [general: expand info on Policy execution available in PolicyResult]

We are using ExecuteAndCapture in our application, the policy is defined in configuration but executed elsewhere. I'd like to log whether a retry has happened (and how many) but all I have is PolicyResult to work from.

In one part of the app, we define a function which builds a policy:

config.BuildExceptionPolicy(() => Policy.Handle<IOxception>().RetryAsync(2));

And execute it in another:

var policy = step.BuildExceptionPolicy();
return policy.ExecuteAndCaptureAsync(async () => { ... } );

If the outcome is Failure, I log the final exception but along side that I'd like to log the number of attempts that were taken.

Tweak class structure (eg distinguish CircuitBreaker and Retry types, clarify relationship between Contextual and non-Contextual)

Polly currently has a class Policy which does not distinguish whether the configured implementation is a retry policy or circuit-breaker policy.

Having separate CircuitBreakerPolicy and RetryPolicy types deriving from an abstract base class Policy could allow library users to specify (eg in parameter types) that they expect an instance of RetryPolicy specifically and not a CircuitBreakerPolicy.

(Use Case: In our microservices implementation, for certain calls we allow callers to pass in the retry policy or circuit-breaker policy (but specifically one or the other, in certain places) they want to use. Because the Polly library at present does not distinguish the types, we cannot use Policy as a parameter type and have ended up having to create our own wrapper classes to distinguish.).

Distinguishing CircuitBreakerPolicy and RetryPolicy types would also allow the introduction of functionality specific to only one type, eg #62

Feature Request/Thought: Ability to control via configuration the Policy and Policy Details

I was wondering if it would be helpful (or a hindrance) if some of the pieces of information such as retry counts and the actual policy being used were configurable thereby preventing the need for a code change but instead a configuration change.

We could have a NuGet package, say Polly.Config, with one dependency (Polly). When installed, it automatically adds a configuration section to the project’s web config as a sort of template to be tweaked:
<configuration>
<configSections>
<section name="RetryPolicies" type="Polly.Config.RetryPoliciesSection.RetryPoliciesSection, Polly.Config" />
</configSections>
<RetryPolicies>
<Policies>
<Policy name="MyRetryPolicy" retryType="WaitAndRetry" retryDelayMs="25,50,75,100" />
<Policy name="None" retryType="None" />
<Policy name="RetryOnce" retryType="RetryOnce" />
<Policy name="RetryNTimes" retryType="RetryNTimes" retryCount="5" />
<Policy name="WaitAndRetry" retryType="WaitAndRetry" retryDelaysMs="50,100,150,200,250" />
<Policy name="RetryForever" retryType="RetryForever" />
<Policy name="CircuitBreaker" retryType="CircuitBreaker" triggerCount="5" timeoutMs="5000" />
</Policies>
</RetryPolicies>
</configuration>

These are just place-holder elements to showcase the available policies and how they should be configured. I added one at the top (i.e. MyRetryPolicy) that is referenced in the code snippet below.

Consuming a named policy in code looks like this (not using a name will default to a policy named “Default”):
public class RetryProvider : IRetryProvider
{
public Task<T> ExecuteAsync<T>(Func<Task<T>> executionFunction)
{
return ConfiguredPolicy.HandleAsync<Exception>("MyRetryPolicy")
.ExecuteAsync(executionFunction);
}
}

If we were to have done this using just Polly, it would have looked something like this:
public Task<T> ExecuteAsync<T>(Func<Task<T>> executionFunction)
{
return Policy
.Handle<Exception>()
.WaitAndRetryAsync(new [] { 25, 50, 75, 100}.Select(x => TimeSpan.FromMilliseconds(x)))
.ExecuteAsync(executionFunction);
}

You can see that all we’ve done is replace the configuration step. Now we can just inject this RetryProvider and use it anywhere we’re going over a network. For example,
RedisValue result = await retryProvider.ExecuteAsync(() => redisCache.StringGetAsync(key));
if (!result.HasValue)
return null;

Again the idea is that it would mean changing the magic numbers of the policy and even the policy itself becomes a configurable piece should that be desired and therefore can be quickly tweaked before and after something like performance testing or in production if problems arise.

Thoughts as to whether this is a good or bad idea?

[WCF-specific] Error Occurs When given timeout and it cannot again because the [WCF] state does not allow Again What do I do?

Exception message:
System.TimeoutException : The opening operation was not completed within the allotted time limit of 00:05:00 . The time allocated for this operation may have been a part of a longer timeout . ---> System.TimeoutException : The socket transfer timed out after 00: 04: 59.9499950 . You have exceeded the time limit set in their association. The time allocated for this operation may have been a part of a longer timeout . ---> System.Net.Sockets.SocketException : A connection attempt failed because the connected party did not answer properly after a period of time, or established connection failed

retry two
Exception message: System.ServiceModel.CommunicationObjectFaultedException: The communication object, System.ServiceModel.Channels.ServiceChannel can not be used for communication because it is in Failed state.

var tentativas = 0;
            var policy = Policy
                .Handle<Exception>()
                .Retry(3,
                    (exception, retryCount, context) =>
                    {
                        Log.LogarErro(string.Format("{0} {1} ", messagemErro, tentativas++), exception);
                    });
            return policy;

I would like Policy to be injectible

I love Polly but i dont like having to have hard coded references to Polly all over my code base. I wonder if you would consider making Policy injectible, maybe by publishing an IPolicy interface?

This would allow me do decouple your implementation from my code easier and i can inject Circuit Breakers into my services.

Ive blogged here (mentioned by Scott Hanselman) about how i solved this issue, but i think it could be made easier.

Circuit breaker - on retry

Hello,

Is there any chance to define method which will should run on exception why executing method? I mean something like in retry method (onRetry)

Retry(this PolicyBuilder policyBuilder, int retryCount, Action<Exception, int, Context> onRetry)

Different retry strategies for different errors

Is it possible to use different retry strategies for different exceptions? Say for Ftp exceptions, I want to retry every 5 minutes while toe Http web API exceptions I want to retry every 10 seconds. Thanks

Make "Polly" unsigned by default and migrate signed to "Polly-Signed"

Hi Michael,

I'd like to propose to introduce a breaking change where by Polly is not
strong named by default. i.e. increment the semver major.

The migration path for existing users who are using strong-names would to be to
migrate to a separate nuget package. i.e.

Signed versions of the client libraries are also available at:

    PM> Install-Package Polly-Signed

This is the path that other OSS packages are taking:

etc.

Important note Binding Redirect is not available w/clients that consume Portable Class Libraries:

Suplemental material:

Thoughts?
Geoff

Not catching FileNotFoundException

Hi,

Your Polly looks very easy and simple to use.
However, i'm having trouble getting it to catch and retry on FileNotFoundException.

Any help or guidance would be much appreciated.

        private static void Main(string[] args)
        {
            byte[] result = {};
            var policy = Policy
                .Handle<FileNotFoundException>()
                .WaitAndRetry(1,
                    retryAttempt => TimeSpan.FromSeconds(2));

            result = policy.Execute(async () => await GetExcelAsync(Guid.NewGuid().ToString())).Result;
            Console.WriteLine(result.Length);
            Console.ReadLine();
        }

        private static async Task<byte[]> GetExcelAsync(string fileId)
        {
            var httpClient = new HttpClient();
            var res = await httpClient.GetAsync("somefileservice" + fileId);
            if (res.StatusCode == HttpStatusCode.NoContent)
                throw new FileNotFoundException();
            if (res.StatusCode == HttpStatusCode.OK)
                return await res.Content.ReadAsAsync<byte[]>();

            throw new Exception();
        }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.