-
Notifications
You must be signed in to change notification settings - Fork 967
Extract AbstractRetryingClient.State into RetryContext and RetryCounter
#6411
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
base: main
Are you sure you want to change the base?
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #6411 +/- ##
============================================
- Coverage 74.46% 74.09% -0.37%
- Complexity 22234 23027 +793
============================================
Files 1963 2064 +101
Lines 82437 86166 +3729
Branches 10764 11310 +546
============================================
+ Hits 61385 63847 +2462
- Misses 15918 16906 +988
- Partials 5134 5413 +279 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
…d before retrying completed
We do not offer retry customization at the moment. In a later PR we will add an API to pass in a custom counter (and scheduler).
core/src/main/java/com/linecorp/armeria/client/retry/RetryingClient.java
Show resolved
Hide resolved
jrhee17
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, this looks a lot easier to review.
Whilel looking at the overall APIs, I was curious how this will be used for hedging.
I was imagining there would be a single method which invokes retry attempts and returns a representation of the asynchronous result so that it could be later used to complete the original response or be cancelled.
(e.g. RetryAttempt retry(RetryContext))
Let me know if I'm missing anything
|
FYI: This PR is not exclusively for hedging. This PR is more of a cleanup so we all can better argue about Let me address your question anyway.
Abstracting away a single retry and returning some kind of handle is certainly something we need to do for hedging, yes. This is because we want to easily start the original retry as well as schedule the hedged one while keeping a reference to the attempts in order to abort the one that does not get committed/ that looses. Compare to the other changes this is a fairly simple and small change we can do when implementing hedging. Maybe to give you a general overview, here are the things we need to have for hedging later on:
For 3.,4., and 5. I would use the Originally, 1. and 2. were done by the For 2. I think we can solve it via a For 1. and 2. we would have to think carefully about concurrency though.
|
|
Hi @jrhee17, do you have any updates on this? |
|
Sorry about the delay, just got back from a long vacation
Sounds good to me 👍 Just wanted to make sure of the plan after this PR is merged.
I prefer that hedging is implemented first so that we can be sure that refactoring isn't done just for the sake of refactoring (unless there is a good reason to do so like done in this PR). While cleaner code is always appreciated, I think it's difficult to judge whether a refactor really helps since we never know how the code/requirements will evolve unless the benefit is very obvious. It would also help convince other maintainers as well. |
jrhee17
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Checked that there aren't any obvious regressions (or at least I couldn't find any)
| null); | ||
| } catch (Throwable cause) { | ||
| duplicator.abort(cause); | ||
| handleException(ctx, rootReqDuplicator, future, cause, false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question) Is there reason why this call was removed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems to be a slip-through; will correct that
Sure, I will have some time in the upcoming week but then I will get less available. So if I can get green light on this refactoring also from other maintainers I can build the e2e hedging prototype on top of that |

Motivation:
Currently,
AbstractRetryingClientmanagesctx.attr(STATE), whileRetrying(Rpc)Clientpasses a "backpack state" by forwarding multiple parameters through internal methods. This leads to several issues:Retrying(Rpc)Clientharder to read and changes to it error-prone, as some parameters share the same types.AbstractRetryingClientandRetrying(Rpc)Client, reducing readability.This PR removes
AbstractRetryingClient.State, splitting it intoRetryContextandRetryCounter, which are now owned byRetrying(Rpc)Client. All methods referencingAbstractRetryingClient.Stateare removed. With thatAbstractRetryingClientis left with only two non-trival methods:getDelayandscheduleNextRetry. As we plan to also extract scheduling from and then deleteAbstractRetryingClientin a later PR,AbstractRetryingClientis already made private to simplify the overall change process to the public API [1].Finally, the PR updates
Retrying(Rpc)Clientto use the newRetryContextand refactors its code for improved clarity.Modifications:
AbstractRetryingClientprivateRetryCounterand move counting state and logic fromAbstractRetryingClient.Stateinto itRetryContext, an immutable value class holding the non-attempt specific retry state fromAbstractRetryingClient.Statelike the original request orHttpRequestDuplicatorAbstractRetryingClient.StateRetryAttempt, an immutable class holding the attempt context and responseRetrying(Rpc)Clientfor better readabilityResult:
AbstractRetryingClientis now private.RetryingClientandRetryingRpcClient[1]: Making
AbstractRetryingClientprivate should be less of a problem anyways asAbstractRetryingClientwas likely not overridden and customized as the current design makes it hard to do so correctly. This is of course is not guaranteed and as such need to be considered if we need to provide a migration path. At the moment I did not implement one but please let me know if you think this is necessary.