Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding the semantics of Polly policies when separating policy definition from execution

Tags:

c#

.net

polly

With Polly I'd like to have my policy definition and the execution of that policy in two different statements, as in:

// Policy definition
var policy = Policy
   .HandleResult<IRestResponse>(predicate)
   .Retry(2);

// Policy execution
policy.ExecuteAndCapture(() =>
{
    DoSomethingAndReturnAnIRestResponse();
};

I want to do it this way so I can get better reuse of my retry policies, e.g. for use in dependency injection.

I'm trying to understand if there's any considerations when splitting up the policy and the execution in this way, for example if there's any "state" (for lack of a better term) that might not carry in the policy object from policy definition to execution.

Along these lines I'm noticing that when I use Polly's ExecuteAndCapture() in the above fashion that certain properties (those related to capturing the final exception/outcome, associated with ExecuteAndCapture()) aren't showing on the policy object. Per the documentation (here and here), upon completion of a policy such as the below:

var policy = Policy
   .HandleResult<IRestResponse>(predicate)
   .Retry(2)
   .ExecuteAndCapture(() =>
    {
       DoSomethingAndReturnAnIRestResponse();
    });

...you are supposed to get back:

PolicyResult.Outcome
PolicyResult.FinalException
PolicyResult.ExceptionType
PolicyResult.Result

This indeed is happening then the ExecuteAndCapture() is in the same statement as the policy definition. However, when separating the policy definition from the execution those properties aren't available. I naively assumed they'd show up on the existing policy object, but they don't:

enter image description here

It seems I need to create a new variable assignment in order to access to those properties:

New policy variable with outcome

Any concerns here?

like image 587
Howiecamp Avatar asked Jun 09 '17 20:06

Howiecamp


People also ask

What is Polly policy?

Polly is a . NET library that provides resilience and transient-fault handling capabilities. You can implement those capabilities by applying Polly policies such as Retry, Circuit Breaker, Bulkhead Isolation, Timeout, and Fallback.

What is circuit breaker Polly?

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 so forth. It is a mature library that is almost synonymous with app resiliency.

How does Polly retry work?

With only a few lines of code, Polly can retry failed requests, cache previous responses, protect your resources, prevent you from making requests to broken services, terminate requests that are taking too long and return a default value when all else fails. It's also thread safe and works on sync and async calls.


1 Answers

No concerns. Configuring policies separate from their usage, and injecting them into sites of usage, is a common pattern which we use extensively in production.

All Polly policies are thread-safe and may be used across multiple independent call-sites concurrently.


Two kinds of Polly policy thread-safely maintain internal state across calls, to carry out their designed functions. This leads to specific (intended) effects if you share those policy instances across call sites.

CircuitBreaker / AdvancedCircuitBreaker

The raison-d'etre is to count and act according to success/fail metrics across calls placed through the policy. Each single policy instance maintains this state for itself internally.

The (intended) functional consequence of this is that if you share a CircuitBreakerPolicy instance in multiple call sites, those multiple call sites will share circuit state, as discussed here.

  • Share the same breaker policy instance across call sites when you want those call sites to break in common - for instance they have a common downstream dependency.
  • Don't share a breaker instance across call sites when you want those call sites to have independent circuit state and break independently.

Bulkhead

The raison-d'etre is to limit concurrency of calls placed through it. Each single BulkheadPolicy instance maintains state internally to track that.

The (intended) functional consequence of this is that when you share a BulkheadPolicy instance across call-sites, those call-sites share the bulkhead capacity between them.

  • Share the same BulkheadPolicy instance across multiple call sites when you want call sites to share the bulkhead capacity between them.
  • Don't share the same BulkheadPolicy instance across multiple call sites when you want them to have independent bulkhead capacity.

No other kind of Polly policy maintains internal state in the policy instance across executions.


.ExecuteAndCapture(...)

The result of an .ExecuteAndCapture(...) call is not on the policy in either of the cases in the question. In both cases (definition and execution in one statement; or separated), the result of the .ExecuteAndCapture(...) call is a fresh PolicyResult instance.

Each execution returns a fresh PolicyResult instance. PolicyResult is never stored as state on a policy instance (that would make policies not thread-safe and re-useable across call sites).

Change var to the actual type (Policy or PolicyResult) in each code location, and this may be clearer to see.

like image 179
mountain traveller Avatar answered Sep 28 '22 16:09

mountain traveller