Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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
Network: Retry requests that failed in flight #6567
Network: Retry requests that failed in flight #6567
Changes from 9 commits
3360e84
3974014
1371639
4029c72
24a91ef
7489bfb
b3e3ba6
badccf5
2a2c367
262469d
3045aca
b1e2a39
d3a9d1c
a2b45ec
6b5a5d1
99e57e6
2fd5104
c3a0e5c
13397ea
470eaaa
294a8f1
File filter
Filter by extension
Conversations
Jump to
There are no files selected for viewing
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.
NAB, just rubber ducking... so we don't need to return this promise anymore because we are handling the promise in
retryRequest()
. Makes sense and looks clean.However, when we previously successfully called
reauthenticate()
we were callingaddDefaultValuesToParameter()
and passing in the original parameters (noauthToken
present there) and the comment seems to suggest that we are getting a newauthToken
to use (the one set locally insidereauthenticate()
)App/src/libs/API.js
Line 294 in 021ad5d
It does look like we will add those parameters here when making the request
App/src/libs/Network.js
Line 222 in 021ad5d
I'm guessing that this is fine because the request we are passing to this callback here
App/src/libs/Network.js
Lines 221 to 229 in 021ad5d
Should never have an
authToken
in it'srequestData
...?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.
TL;DR is the existing code here just pointless?
App/src/libs/API.js
Lines 112 to 117 in 021ad5d
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.
That makes sense - only add (the latest) token for authenticated requests and don't expect it to be part of
requestData
Yeah, it unneeded but it also might be a subtle bug calling
addDefaultValuesToParameters
here. It would addauthToken
to original params which might get persisted, and might expire, but won't be possible to update:App/src/libs/API.js
Lines 75 to 77 in 7af06bc
It might be best to update the enhancer to always add the latest token
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.
Cool. Maybe we can address this in a follow up issue if it becomes a problem. Not sure I am seeing the subtle bug yet but does sound like maybe persisted requests should not be saved with the
authToken
and we should always prefer the most recent one we have.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.
Should we pause the request queue right here rather than in
Authenticate
? Because we know on line 155 if we're going to try to reauthenticate, so maybe we should immediate pause the request queue so that another request doesn't begin processing before we attempt to reauthenticate?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.
No need to - it's impossible for another requests to start
Whether the call is now or "a few lines later" inside
Authenticate
it's still executed as sync code, which makes it impossible for other requests to startThe unit tests are covering this: "Multiple Authenticate calls should be resolved with the same value"
we start 5 requests at the same time - if pausing didn't work as expected it would have let another request to start
Putting the "pause" anywhere else but in Authenticate, only hides details that might be important and scatters the logic around
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.
more opinion than fact (in my opinion 😄)
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.
So you both think we should pause while authenticating, call the pause outside of
Authenticate
but call the unpause from insideAuthenticate
?The original code was pausing the Network queue in
handleExpiredAuthToken
clearly the intent was to prevent any (other) requests while authentication runs.Besides running
Authenticate
would change the token so it's best to pause any requests, otherwise they will happen in the middle of authentication and get rejected, causing a new authenticate and then retry the actual callSince authenticate and reauthenticate are exported, they can and are triggered from outside (pusher)
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.
Correct me if wrong, but this here seems to be the main material change?
If we get a network error (like a fetch error) now we just toss the request into the ether instead of retrying it?
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.
If that's correct. I'm sort of confused why we are doing this here instead of when we call
onError()
hereApp/src/libs/Network.js
Lines 226 to 228 in 021ad5d
Could we just add the request to the array of requests to retry instead?
App/src/libs/Network.js
Lines 243 to 245 in 021ad5d
Seems easier to do that and then we won't need
onError()
to callretryRequest()
which callsNetwork.post()
etc.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.
The opposite actually. When we get a network/fetch error we'll get right here where we retry if we're supposed to.
It happens inside
onError
aka theErrorHanlder
because weAre you suggesting something like
If we shouldn't log or call
setSessionLoadingAndError
we could move the retry toNetwork
. The only problem would be that we have aonError
handler that's not handling all the errorsBesides the
SuccessHandler
also retries the request throughNetwork.post()
, but if it were tothrow
on expired token it would trigger thecatch
block and reschedule the request through the same logicOne thing to note in advance - the following is not possible:
onError
would reject the underlying promise and it won't be possible to resolve or reject it anymoreThere 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.
Yes, sorry I am describing the current behavior (without your changes)
I see your point about losing the logs. But we could also:
onError()
because we don't need to reject the promise or callsetLoadingAndError()
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.
Sounds like a plan
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.
I'm saying that we already have a
retry
logic inside API (calling Network.post)And we're discussing whether we should add another
retry
logic in Network (to spare us from calling Network.post, and to reuse canRetry)Let's keep using
Network.post
to retry the request like we do in the Response Handler (expired token)It would still aid refactoring, when we identify exactly how it should happen
On one side (Network) we
canRetry
On the other
❔ - is it really good or bad?
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.
Are these the only possibilities we should expect to see? And if so and these should be deploy blocking events why would the proposed solution be to retry them? Should we maybe at least queue a log to alert in such cases in addition to retrying over and over?
Sorry, I'm not quite seeing where the eventual success happens.
As I mentioned already, I don't see a compelling reason to do it this way so it's not worth having this many back and forth exchanges to resolve.
Regardless, it seems more important to figure out how to handle the infinite retries concern.
I'm not sure if there's a way to wrap that concern up quickly. But without a proposal to do so I'm not sure it's a great idea to retry these requests.
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.
I'm not suggesting to retry those, but the error itself doesn't carry information to distinct them -fetch
would just callcatch
with an unspecificFailed to fetch
error. Supposedly this is by design to prevent exploitsWe can't distinct what caused an error. A network error can be caused by:
The most likely reason to be in the
catch
handler is that we're either offline or we've experienced a fluke and can recover by retrying the requestTo your point for prevent infinite loop of requests we could only retry the request if
I've edited my last reply with pros / cons, but if that's not making sense just tell me what you need done:
console.debug
If the reason for a request to fail is purely network related and not the actual payload we should retry it - same reason we retry it after re-authentication or why we post it after it has been persisted in storage be it a minute or a year
Because we "promise eventual delivery"
Let's say there's a CORS error and posting chat messages stops working - there's nothing you can do on the front end to fix the issue. Instead of commiting to data loss and discarding the requests we can
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.
The reason to retry the request, besides everything else said
When we fail to reach the API for any reason - retry the request (if it's retriable)
Keep the logic simple we can extend it if it becomes a problem
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.
Sure, sorry for being indirect - that new plan sounds good for now
It would be good to log when the request happens so maybe next we can solve the circular dependency issues in a new PR.
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.
Would you mind explaining (briefly) the motivation behind moving this logic into
Authenticate()
instead ofhandleExpiredAuthToken()
? Didn't quite figure it out from looking at the PR.Could we theoretically leave the
pendingAuthTask
idea and put this logic back intohandleExpiredAuthToken()
where it was and achieve the "retry requests that fail in flight" objective?Feels like
isAuthenticating
was swapped forpendingAuthTask
. Is there a clear reason to prefer one over the other?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.
I've actually made a comment about it here:
Sure, would you like me to open a separate PR about it?
Capturing a
Promise
insidependingAuthTask
allow us to hook other callers to the same Authentication call rather than starting a new call.If Authentication is already in progress when you call
Authenticate
you should hook to it, rather than starting a new call and potentially invalidating the result of the one that's already runningThere 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.
Yeah, maybe we can create a new issue for this as well? I'm not quite seeing the path for how this can happen or why we should be concerned about it - but guessing you would be able to document it and we can address it separately if it's concerning?
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.
What does this mean? If we are "pausing" the request queue what requests are being made?
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.
Pausing the queue doesn't prevent you from making actions that trigger a
Network.post
I'm saying anything pending or added to the network queue has to wait until we're authenticated.
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.
I know this is copied from elsewhere but think it would be good to take the opportunity and explain
pendingAuthTask
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.
Sure that ppl would be open to hearing your thoughts on why these extra docs are useful or we should do it. But most people are not adding them consistently so I think they should be removed.
I'd recommend: