-
Notifications
You must be signed in to change notification settings - Fork 3k
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: Persisted Requests Queue - clear persisted requests after the response #6556
Network: Persisted Requests Queue - clear persisted requests after the response #6556
Conversation
One less SESSION connection
Move more Onyx related handling as we're already dealing with saving and clearing here
Use _.isEqual to skip adding requests that we might already have persisted and the same when removing to remove only the matching request
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.
Added some highlights on the changes
// Unless email is already set include current user's email in every request and the server logs | ||
finalParameters.email = lodashGet(parameters, 'email', currentUserEmail); |
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.
This was originally part of the network "forEach" here:
Network.js
// If we haven't passed an email in the request data, set it to the current user's email
if (email && _.isEmpty(requestEmail)) {
requestData.email = email;
}
const finalParameters = _.isFunction(enhanceParameters)
? enhanceParameters(queuedRequest.command, requestData)
: requestData;
Here (addDefaultParameters) seems to be a better place for this logic
// Do a recursive call in case the queue is not empty after processing the current batch | ||
return Promise.all(tasks) | ||
.then(processPersistedRequestsQueue); | ||
} |
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.
We can have remaining requests when
- the request failed for some reason and is not removed from the queue - as seen in the catch block
- we became offline again, which would again lead to the catch block above. In that case the queue would still stop and will be retriggered once we're back online, more requests can be added to it in the meantime
Not sure if we should capture that in a comment or something
@@ -328,7 +316,6 @@ function clearRequestQueue() { | |||
export { | |||
post, | |||
pauseRequestQueue, | |||
PROCESS_REQUEST_DELAY_MS, |
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.
This is now exported from CONST.NETWORK.PROCESS_REQUEST_DELAY_MS
and usages updated
function incrementRetries(request) { | ||
const current = retryMap.get(request) || 0; | ||
const next = current + 1; | ||
retryMap.set(request, next); | ||
|
||
return next; | ||
} |
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.
Retry counts are not persisted to disk - no need to
If a request is retried 5 times then the app quit, when the app is launched again the request will have a fresh count of up to 10 attempts, and not only the remaining 5
Might be an edge case but I think it would be best to have a retry limit in case some corrupt data was persisted and it cannot be sent no matter how many times we try.
That's why we keeping a count per request here and we forfeit a request after the count grows past a certain limit (CONST.NETWORK.MAX_PERSISTED_REQUEST_RETRIES)
@roryabraham do you mind co-reviewing this with me? |
let isQueuePaused = false; | ||
let persistedRequestsQueueRunning = 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.
It's interesting that this value is sort of the inverse of isQueuePaused
. I think we should try to keep these two things consistent, so maybe one of the following two options:
let isQueuePaused = false;
let isOfflineQueuePaused = true;
or
let isMainQueueRunning = true;
let isOfflineQueueRunning = 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.
The name comes from this usagage and readability reasons
This method is starting something rather than making it not paused
function flushPersistedRequestsQueue() {
if (persistedRequestsQueueRunning) {
return;
}
persistedRequestsQueueRunning = true;
vs
function flushPersistedRequestsQueue() {
if (!persistedRequestsQueuePaused) {
return;
}
persistedRequestsQueuePaused = false;
running is the "special case" for this queue, while paused is the special case for the regular queue
I'm reluctant to refactor isQueuePaused
to isMainQueueRunning
it would change usages and might affect their intent as well, also it kind a sound like we're online too
I had only surface-level comments on this implementation, but will bring higher-level discussion to the linked issue. |
This is ready for review |
@johnmlee101 @roryabraham can you review this PR? @kidroca 's been waiting three weeks |
Sorry, this accidentally got closed: #4908 (comment) |
@johnmlee101 @roryabraham |
Oh, I see there are conflicts |
@johnmlee101 @roryabraham @mallenexpensify |
I think the changes right now are good, and I'll be ready to approve once the conflicts are resolved. |
Yeah, I looked this over again and I don't think I have any further comments. |
I'll submit a merge and fix conflicts shortly |
# Conflicts: # tests/unit/NetworkTest.js
Synced with main and retested - everything working as intended |
✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release. |
🚀 Deployed to staging by @roryabraham in version: 1.1.33-4 🚀
|
🚀 Deployed to production by @sketchydroide in version: 1.1.34-0 🚀
|
} | ||
|
||
function saveRetryableRequests(retryableRequests) { | ||
Onyx.merge(ONYXKEYS.NETWORK_REQUEST_QUEUE, retryableRequests); | ||
persistedRequests = lodashUnionWith(persistedRequests, retryableRequests, _.isEqual); |
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.
This change has introduced this bug. (Title: pinned chat become unpinned when user pinned chat in offline mode)
If a user takes an action that is identical(_.isEqual) to older action then it will be removed.
To fix the issue we have replace above code by:
persistedRequests = persistedRequests.concat(requestsToPersist);
The PR that fixes the issue: #14608
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 idea is to prevent the user from accumulate duplicate requests while offline
If you perform the same action 10x while offline, we skip posting 10 Network request but just one
This is an optimization that helps users in low network conditions to not waste bandwidth
From the information shared here it seems that pinning and unpinning the chat uses the same command / request, I would suggest to make them distinct actions so that _.isEqual
can differentiate them correctly
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.
We shouldn't have done this. Context https://expensify.slack.com/archives/C01GTK53T8Q/p1685822789307339
Details
Additional functionality was added to
Network.js
andNetworkRequestQueue.js
to better handle persisted requestsAdded unit tests covering persisted request handling
Fixed Issues
$ #5987
Tests
QA Steps
Follow the steps from the bug report
This comment has additional details on steps and timing: #5987 (comment)
Tested On
Screenshots
Web
New.Expensify.-.Google.Chrome.2021-12-01.12-51-05.mp4
Mobile Web
Android.Emulator.-.Pixel_2_API_29_5554.2021-12-01.13-11-03.mp4
Desktop
Screen.Recording.2021-12-01.at.13.22.10.mov
iOS
Screen.Recording.2021-12-01.at.14.45.00.mov
Android
Android.Emulator.-.Pixel_2_API_29_5554.2021-12-01.08-49-22.mp4