-
-
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
Anti-patterns for Retry in V7 #1527
Comments
This looks really great! |
Do you have any ideas on how to approach this from the perspective of V8? |
IMHO the root cause of these anti-patterns (in most of the cases) is that the APIs are flexible enough to achieve same behavior with different chain of method calls.
So, I think we could iterate through the patterns one-by-one and assess them by answering to the following questions:
What do you think? |
Based on the description only the number 3 is not possible with V8. The remaining ones are all doable with V8. |
Cool, one less anti-pattern :D Would you convert the V7 code snippets to V8? |
I can give it a shot. It should be pretty straightforward. The main difference is that in V8 the strategies (policies) are executed in the same order as they were added. For example, this: var quickRetries = ...
.WaitAndRetry(Backoff.DecorrelatedJitterBackoffV2(TimeSpan.FromSeconds(1), 5));
var slowRetries = ...
.WaitAndRetry(5, TimeSpan.FromMinutes(3));
var retries = Policy.Wrap(slowRetries, quickRetries); Now becomes: var pipeline = new ResiliencePipelineBuilder()
.AddRetry(new() // slow retries
{
MaxRetryAttempts = 5,
Delay = System.TimeSpan.FromMinutes(3),
BackoffType = DelayBackoffType.Constant
})
.AddRetry(new() // fast retries
{
MaxRetryAttempts = 5,
Delay = System.TimeSpan.FromSeconds(1),
UseJitter = true,
BackoffType = DelayBackoffType.Exponential
})
.Build(); |
As it was discussed in this PR I've tried to collect those anti-patterns what I have seen in past 3+ years on StackOverflow.
In this issue I try to focus only on Retry. Later I will file new issues for Fallback, Circuit Breaker, etc..
1 - Using retry as a periodical executor
The retry policy can be defined in a way that it runs forever in a given frequency for example once in a day
❌ DON'T
Reasoning:
✅ DO
Use appropriate tool to schedule recurring jobs like Quartz.Net or Hangfire
Reasoning:
2 - Combining multiple sleep duration strategies
The retry has several overloads where you can dynamically define the sleep durations
❌ DON'T
Mixing the ever an increasing values with constant ones
Reasoning:
retryCount
parameter of the policy✅ DO
Define two separate policies and then chain them
Reasoning:
3 - Pre-generating massive amount of sleep durations
WaitAndRetry
can can accept anIEnumerable<TimeSpan>
for sleep durations❌ DON'T
Creating a
List
with huge amount of timespansReasoning:
✅ DO
Use
yield return
andsleepDurationProvider
Reasoning:
4 - Branching retry logic based on request url
Lets suppose you have an
HttpClient
and you want to decorate it with a retry only if a request is against a certain endpoint❌ DON'T
Using
NoOp
and?:
operatorReasoning:
✅ DO
Use the
Handle
/Or
clauses to prevent triggering retryReasoning:
5 - Calling a given method before/after each retry attempt
The
onRetry
/onRetryAsync
user-defined delegates are called before the sleep❌ DON'T
Calling explicitly the given method before
Execute
/ExecuteAsync
Reasoning:
onRetry
is called before each retry attempt it won't be called before the very first initial attempt (which is not a retry)BeforeEachRetry
before everyExecute
callsBefore
so, one might call it after theExecute
call which is not the intended behaviour✅ DO
Decorate the method call pair together
Reasoning:
DoSomething
andBeforeEachRetry
coupled together then decorate them together6 - Having a single policy to cover multiple failures
Lets suppose we have an
HttpClient
which issues a request and then we try to parse a large Json❌ DON'T
Having a single policy to cover everything
Reasoning:
X
andY
coupled together then decorate them together✅ DO
Define a policy per failure "mode"
Reasoning:
7 - Cancelling retry in case of given exception
After you receive a
TimeoutException
you don't want to perform any more retries❌ DON'T
Adding cancellation logic inside
onRetryAsync
Reasoning:
Handle
/Or
/HandleResult
/OrResult
builder methodsException
or by aCancellationToken
just complicates the policy (and its control flow) unnecessarily✅ DO
Define triggering logic inside
Handle
Reasoning:
The text was updated successfully, but these errors were encountered: