-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Expected diamond-depndency conflict if multi-versions referenced and third-party component does not update - does not affect HttpClientFactory [ System.TypeLoadException when referencing both Polly 7 and transitive Polly 6 ] #615
Comments
Hi @altso , thanks for the exemplary repo. You can solve this by forcing the project indirectly referencing Polly 6.x (the project The yellow-highlighted nuget reference to Polly v7.0.3 is the one you have to add. The indirect reference to Polly via Microsoft.Extensions.Http.Polly (marked red) then falls into line and also references Polly v7.0.3. The app then builds and starts successfully. There is nothing in the Microsoft extensions to Polly which rely specifically on Polly v6 features, so this is a safe procedure. Here is a zip showing the fix: Issue615fix.zip For completeness for all coming to this issue in future Polly v7.0 clarified the sync/async split internally in Polly policies, but no actual change in functionality on that. The only other breaking change in Polly v7 is changes to cache provider interfaces. For cache providers which the Polly team maintains (Polly.Caching.Memory, Polly.Caching.Distributed and Polly.Caching.Serialization.Json), we have already released upgraded cache providers. Thus, the only cases in which following the above procedure - forcing a Polly v7.x on an external dependency which currently references v6 - could cause a problem, , would be if the third-party component was an implementation of a custom Polly cache provider for CachePolicy, where that third-party custom cache provider had not yet updated for the v7 changes. |
@reisenberger, thanks for the prompt reply. Adding an explicit package reference to |
Hi @altso . I want to be sure I haven't misunderstood the question, but I think the case discussed does illustrate a third-party library. In the above example, Does that make sense, or is there a case you are thinking of which I am not seeing? Sidenote: Where this would not work would be if a third-party library had restricted their library from inter-operating with versions of Polly higher than v6, eg with a dependency directive such as:
But it would be against common/recommended practice for a library to have done that, as per eg the Microsoft diamond dependencies page ("Avoid NuGet package references with a version upper limit"). And there would be no reason for a library referencing Polly to have done that - unless they are a cache provider release only compatible with v6. |
@reisenberger apologies for the confusion. I'll try to explain better. Let's assume
Even though it's similar to how
In case of Hope this clarifies my questions. I can create a complete example by publishing |
Hi @altso. Ok, let's try it. No need to publish the nuget package to public nuget: you can also drag the |
@reisenberger I updated the example. Please see this commit altso/PollySeven@7a94985. I used this command to make a package:
You can download the binary here: https://github.com/altso/PollySeven/blob/master/LocalPackageSource/PollySeven.MyHttpClient.1.0.0.nupkg?raw=true |
Thanks @altso, that's a great example. I see how this arises. Agreed that the breaking changes in v7 mean that an app fails with a runtime failure in this diamond-dependencies-conflict case. Note that this is a common concern for OSS libraries, not unique to Polly. To your question:
If this arises (... I am assuming this is a hypothetical now; do say if not), we could: (a) Publish a new version of Polly, v8, which undoes the internal rearrangements to Polly code in v7 which are a partial cause; or (EDIT: I should have been clearer that I listed (a) (going backwards) to suggest that it was not really a serious option... ) You can see the dilemma. I think the sensible position for me as a library maintainer is to recommend (b). ;~) This is a general question for any OSS library. OSS libraries evolve - we cannot (in a general sense) be held back from evolving by third-parties who may choose not to evolve with us. On the other hand, of course we have a responsibility to promote stability in the ecosystem and strive to avoid frequent breaking changes. In general on Polly we have promoted stability for a long time (no breaking changes for 10 months ... then for 18 months before that ... ... tho not sure that is always a good metric: there are significant breaking changes to Polly syntax (edit: also not affecting httpclientfactory) that it would be good to introduce to open up new development paths!). I hope that makes sense for now? Open to feedback if people think we are getting this wrong. If a case arises, let's tackle it, but my instinct is that the first approach for your question should be (b). |
@reisenberger thanks for looking into that. The issue arose in a couple of internal nuget packages and we fixed that by adding an explicit reference to Polly v7 in each of them. I do not think option (a) is a way to go as you will introduce a breaking change between v7 and v8. I also think option (b) is better but not ideal as it requires additional work from other devs who might not be aware of the issue at all. A colleague of mine suggested another approach. Let's call it option (c): (c) Bring back all the missing types and methods with the same exact signatures as they had in v6, but provide a bridge to v7 implementations. Something like this: using System;
using System.ComponentModel;
namespace Polly
{
[Obsolete]
[EditorBrowsable(EditorBrowsableState.Never)]
public static class RetryTResultSyntaxAsync
{
[Obsolete]
[EditorBrowsable(EditorBrowsableState.Never)]
public static RetryPolicy<TResult> RetryAsync<TResult>(PolicyBuilder<TResult> policyBuilder)
{
// The line below actually does not compile as there is no conversion
// between AsyncRetryPolicy<TResult> and RetryPolicy<TResult>.
// Call the new api via extension method
return policyBuilder.RetryAsync();
}
}
} Please note:
If not mistaken, that should bring back the binary compatibility between v6 and v7. Unfortunately, I do not know how to make the code above compile and work properly at the moment - just an idea, but I can take a deeper look if you think it's worth it. Let me know. Also, that would be less of an issue if |
Thanks @altso for the deep engagement on this issue. Re the fact that (a) would introduce another breaking change: yes, very much so, hence (per semver) my flagging that the replacement would be v8. I agree that an approach along the lines of (c) might be possible in principle (not tried it, but I see the logic...), but in this case I think we cannot achieve it. We cannot:
because, as you observe, the return type for the async policies has (intentionally) changed so that they are now separate There is also a fourth approach I forgot yesterday: (d) I haven't tried this, and don't know if But (b) is the obvious preferred route. The HttpClientFactory case is already solved per my earlier comment. I've added guidance on this on both the Polly v7 page and Polly with HttpClientFactory page. |
Thanks for the clarification @reisenberger. It sounds like there is no way to mitigate this issue in Polly itself. Option (b) worked for me and hopefully will work for others as well. |
Thanks @altso . I'm going to close this out as I think we're concluded, but please do re-open if you have further comments/questions; the discussion has surfaced lots of useful detail. TL;DR It's the result of an (intended) breaking change between Polly v6 and v7; and yes, diamond-dependency conflicts are a fact of life in the ecosystem if third-party libraries do not update. |
Assuming a solution with the following project/code structure:
PollySeven.MyHttpClient
depends onMicrosoft.Extensions.Http.Polly
(which depends onPolly
v6).PollySeven.MyHttpClient
usesRetryAsync()
extension method to registerMyService
.PollySeven
depends onPollySeven.MyHttpClient
andPolly
v7.PollySeven
usesMyService
.PollySeven
PollySeven.MyHttpClient
When the application runs, I get
System.TypeLoadException
.The root cause of this issue might be similar to #611.
Expected behavior:
Code executes successfully.
Actual behaviour:
System.TypeLoadException
is thrown:Steps / Code to reproduce the problem:
Example repo: https://github.com/altso/PollySeven
The text was updated successfully, but these errors were encountered: