[Proposal] Should we keep or remove the non-generic `ResilienceStrategy`
See original GitHub issueRecent enhancements to ResilienceStrategy<T>
(#1428) have significantly improved the usability of generic resilience strategies, expanding use-case scenarios:
ResilienceStrategy<object> strategy = NullResilienceStrategy<object>.Instance;
int v1 = strategy.Execute(() => 10);
string v2 = strategy.Execute(() => "val");
bool v3 = strategy.Execute(() => true);
This progress paves the way for potential removal of the non-generic ResilienceStrategy
type and associated infrastructure. This proposal brings both advantages and disadvantages that should be thoroughly assessed before making a decision.
Advantages
- Reduced API Surface: This major advantage simplifies maintenance efforts.
- Inherent Support for Reactive Strategies: Currently, reactive strategies utilize OutcomeResilienceStrategy as a base class, bridging
ResilienceStrategy
toResilienceStrategy<T>
. This change would render the bridge class obsolete, integrating support for reactive strategies directly.
Disadvantages
- Complex Strategy Composition: The existing resilience strategy implements
ResilienceStrategy
, which lacks a generic constraint, facilitating strategy composition. If non-generic strategies are removed, the newResilienceStrategy<T>
signature would restrict composability to strategies ofT
orResilienceStrategy<object>
. - Imposed Constraints on Non-Reactive Strategies: Strategies such as
Timeout
andRateLimiter
are indifferent to result types and can naturally be executed across all result types. Under the new model, these strategies would no longer have this “natural implementation.” - Lack of Inherent Support for
Void
Result Types: The removal ofResilienceStrategy
would eliminate a straightforward method for executing void-based callbacks. While aVoidResult
type could be introduced, usage would be more complex than the existing system. - Complicated Usage of
ResilienceStrategy
: Presently, it’s simple to pass and flowResilienceStrategy
in the API for basic scenarios or when exceptions are exclusively handled by the consumer. In the proposed model, passingResilienceStrategy<object>
feels less intuitive.
Current Usage:
ResilienceStrategy strategy = new ResilienceStrategyBuilder()
.AddTimeout(TimeSpan.FromSeconds(10))
.AddRetry(new RetryStrategyOptions
{
RetryCount = 4,
BaseDelay = TimeSpan.FromSeconds(10),
})
.Build();
ResilienceStrategyRegistry<string> registry = new ResilienceStrategyRegistry<string>();
ResilienceStrategy strategyFromRegistry = registry.GetStrategy("my-strategy");
strategy.Execute(() => "dummy");
strategy.Execute(() => 10);
strategy.Execute(() => { SomeCall(); });
New usage:
ResilienceStrategy<object> strategy = new ResilienceStrategyBuilder<object>()
.AddTimeout(TimeSpan.FromSeconds(10))
.AddRetry(new RetryStrategyOptions<object>
{
RetryCount = 4,
BaseDelay = TimeSpan.FromSeconds(10),
})
.Build();
ResilienceStrategyRegistry<string> registry = new ResilienceStrategyRegistry<string>();
ResilienceStrategy<object> strategyFromRegistry = registry.GetStrategy<object>("my-strategy");
strategy.Execute(() => "dummy");
strategy.Execute(() => 10);
strategy.Execute(() => { SomeCall(); return VoidResult.Instance; });
Contributes to #1365
Would love your feedback and insights on this matter before we proceed with any modifications, as these changes could significantly affect the usability of V8.
@martincostello @joelhulen @juraj-blazek @geeknoid @PeterCsalaHbo @andrey-noskov @vany0114
Issue Analytics
- State:
- Created 2 months ago
- Comments:12 (6 by maintainers)
Top Results From Across the Web
The Quest for Resilience
The Strategic Challenge: Resilience requires alternatives as well as awareness—the ability to create a plethora of new options as compelling alternatives to ...
Read more >A Generic Quantitative Approach to Resilience: A Proposal
This paper proposes a generic quantitative approach to defining and measuring resilience. A simple resilience model is introduced using five critical states of ......
Read more >From Resistance to Transformation: A Generic Metric of ...
We propose to do this through the development of a generalizable metric of resilience. For this we rely on a mathematical formalism—the ...
Read more >3 Resilience and Ecosystem Services | An ...
Considerations of resilience are especially important in systems that undergo persistent and fundamental shifts in structure and function after disturbances ...
Read more >Climate-Resilient Pathways: Adaptation, Mitigation, and SD
Adaptation is considered a response strategy to anticipate and cope with impacts that cannot be (or are not) avoided under different scenarios of...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
I agree that unifying the builders would improve maintainability. However, the new usage looks to me like an API limitation workaround. I believe that
object
should be used sparingly in a type safe language and with this change it would likely be introduced to many use cases that do not care about the result. All this adds to complexity and makes Polly more difficult to use for anyone who just picks it up.To me generic/non-generic is the intuitive way to do it. If I care about a result, I specify the type. If I don’t I don’t specify anything. The unification would be fine, if C# had standard object type for null/void/no data. But instead it treats void special, so I think Polly should do it the same way, not try to be different.
Ease of use is probably the most important thing. If it’s too difficult, people would rather write it themselves, usually all they need is just retries and you can do that fairly easily.
I agree with the others here who believe that removing non-generic strategies has more cons than pros, not least of which is adding complexity where there is no clear benefit in doing so for most developers/use cases. Explicitly using
object
and introducing aVoidResult
type seems hacky and would give our API a bad sense of code smell. I do not think that we should remove the non-generic types.