-
-
Couldn't load subscription status.
- Fork 1.3k
Description
Recent 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
ResilienceStrategytoResilienceStrategy<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 ofTorResilienceStrategy<object>. - Imposed Constraints on Non-Reactive Strategies: Strategies such as
TimeoutandRateLimiterare 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
VoidResult Types: The removal ofResilienceStrategywould eliminate a straightforward method for executing void-based callbacks. While aVoidResulttype could be introduced, usage would be more complex than the existing system. - Complicated Usage of
ResilienceStrategy: Presently, it's simple to pass and flowResilienceStrategyin 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