Skip to content

Polly v6 breaking changes

reisenberger edited this page Sep 8, 2018 · 6 revisions

Polly v6 introduced a number of breaking changes over v5.

Area Summary rationale
Rationalise Execute()/ ExecuteAsync() overloads Reduce the number of overloads; standardise to build a more consistent overload set going forward
Rename ExecutionKey as OperationKey Better communicate purpose; reduce confusion with similar-named key.
Rename ExecutionGuid as CorrelationId Better communicate purpose; reduce confusion with similar-named key.
Publish Polly as strong-named only Avoid diamond-dependency conflicts in the market going forward
Upgrade supported targets Modernise

All changes are deprecated in Polly v5.9 with [Obsolete] attributes.

Rationalise Execute()/ ExecuteAsync() overloads

What changed?

As well as taking the delegate to execute, Polly Execute()/ ExecuteAsync() overloads commonly offer the following two optional parameters:

Parameter Purpose
Context an execution Context, or dictionary data to populate that context
CancellationToken a CancellationToken, when you want to pass a token to control cancellation of the policy or the executing delegate

In Polly v5, some overloads existed where the Context context or CancellationToken parameters were passed but not used as input parameters to the Func<Task> action executed:

Task ExecuteAsync(Func<Task> action, Context context)

With such overloads the passed Context or CancellationToken parameters influenced policy behaviour, but not executed delegate behaviour.

In v6 all such overloads were deprecated in favour of overloads where the action delegate executed takes all passed parameters

Task ExecuteAsync(Func<Context, Task> action, Context context)

Why?

By aligning the parameters passed to ExecuteAsync(...) with the input parameters to the executed delegate, we open up the possibility for adding future generic overloads allowing user-defined input parameters to be passed into executed delegate without the use of closures:

Task<TResult> ExecuteAsync<T1, TResult>(Func<T1, Context, CancellationToken, Task<TResult>> func, T1 t1, Context context, CancellationToken token)

Task<TResult> ExecuteAsync<T1, T2, TResult>(Func<T1, T2, Context, CancellationToken, Task<TResult>> func, T1 t1, T2 t2, Context context, CancellationToken token)

Without the v6 standardisation of overloads this would not be possible.

How to upgrade to v6

If you receive a compilation error that the overload no longer exists in v6, simply add Context or CancellationToken (as appropriate) as an input to the executed delegate.

Note

ExecuteAsync() overloads also offer the bool continueOnCapturedContext optional parameter. This has never featured as an input parameter to async delegates executed through policies and no changes was made to this.

Rename ExecutionKey as OperationKey; ExecutionGuid as CorrelationId

What changed and why?

The following properties on Context were renamed:

Old name New name
ExecutionKey OperationKey
ExecutionGuid CorrelationId

How to upgrade to v6

Use the new property names.

Publish Polly as strong-named only

What changed?

To v5.9 Polly was published as separate nuget packages Polly (unsigned) and Polly-Signed. Signed in the <=v5.9 context actually means strong-named.

From Polly v6.0 only a single package, Polly, is published, and it is strong-named.

Why?

ASPNET Core 2.1 offers deep integration with Polly for HttpClient instances created through HttpClientFactory. This allows the easy application of Polly resilience strategies to outbound calls through HttpClient.

ASPNET Core 2.1 is strong-named so this was expected to significantly increase consumption of a strong-named form of Polly. That however would risk creating diamond-dependency conflicts which apparently have no solution for packages or projects that before then consumed non-strong-named Polly (example) (good summary).

If we had left both non-strong-named and strong-named Polly in the market, we would have prolonged the possibility of these irresoluble conflicts into future months and years. By switching to a single, strong-named Polly release, there was initial impact while products switch to strong-named Polly but the duration of pain is limited by there being only a single version in the market. The single strong-named package strategy is the strategy used by high-download nuget packages such as NewtonSoft.Json, FluentValidation, and Serilog, and is the strategy recommended by the Microsoft ASP.NET team.

Polly v6.0 also adopts the so-called Newtonsoft.Json strategy described here to minimise onward impact:

  • nuget package numbers follow full semver (Major.Minor.Patch increments) to differentiate bug-fixes, new-functionality-without-breaking-changes, and breaking-changes.
  • Dlls partially follow Major.0.0 version numbering only (even if the true version is Major.Minor.Patch). This reduces the burden on projects which consume Polly of introducing excessive assembly binding redirects.

Reference: Further discussion.

How to upgrade to v6

Switch packages as follows:

Old package used New package to use
Polly-Signed Polly
Polly Polly

Both non-strong-named DLLs and strong-named DLLs can reference strong-named DLLs, so whether your project uses strong-naming or not, you will be able to reference the new Polly v6 strong-named packages.

Clone this wiki locally