De-dupe ReconnectApp in the persisted requests queue#47913
De-dupe ReconnectApp in the persisted requests queue#47913roryabraham merged 34 commits intoExpensify:mainfrom
Conversation
|
@sobitneupane Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button] |
|
@roryabraham PR created, ready for review |
roryabraham
left a comment
There was a problem hiding this comment.
I think we should:
- create a more generalized framework for de-duping network requests in the request queue, as is done in this PR
- add back all the other cases that were removed (i.e: if adding
DeleteCommentto the request queue, and there's anyAddCommentorUpdateCommentfor the same reportActionID, then just remove them all from the queue). - Add automated tests
Honestly, I was planning to do this myself because I have good historical context, but I just haven't prioritized it yet. I've finished up a lot of other stuff so might be able to proceed with #40059 now.
|
@roryabraham Nice, I like that idea of making it generic, I didn't know that other requests will need some strategy to fix it. Give that many requests require different strategies, for reconnectApp the structure you made for That way all is encapsulate into one place, into the request creation. |
Maybe I'm not seeing something, but I think it works fine for
|
|
@roryabraham I don’t want to add extra functions that aren’t needed. As an example, Let’s say we have 10 items in the queue, and there is a ReconnectApp at position 4; a new one will be added. The I think the main logic from your PR can be inside the (I'm updating a bit while thinking and finding more cases) |
|
@roryabraham in my last commit It is your code, from the PR, using just one single function, and you can see how reconnectApp will work. What do you think? |
roryabraham
left a comment
There was a problem hiding this comment.
Overall this looks like a good implementation. It's an improvement over what I had in that it identifies the main use-cases we'll have and implements them with better guard rails. Good job 👍🏼
NAB but I kind of prefer replace and push as the actions instead of update and save, because they're a bit more distinctive from each other and better reflect the queue structure.
Also, I'd love to add some automated tests for this before merging it. Thanks!
|
@roryabraham Great approach! It definitely makes sense. I will work on ReconnectApp with the new conflictResolver. This way, each change has its own PR, which makes it easier to track and identify any regressions. After it, we can proceed with looking into the DELETE_COMMENT. What do you think? |
|
Sounds good 👍 |
e915009 to
615a8ba
Compare
|
@roryabraham I added a few tests, I'm giving a round of QA, what else I'm missing? what more tests do you think I should add? |
# Conflicts: # src/libs/Network/SequentialQueue.ts
|
@roryabraham friendly ping |
roryabraham
left a comment
There was a problem hiding this comment.
It's great that we've added tests to cover the underlying logic in SequentialQueue, but I think it's also important that we add test coverage for App.reconnectApp that ensures that our implementation of checkAndFixConflictingRequest is working as expected in that case.
| expect(PersistedRequests.getLength()).toBe(2); | ||
| }); | ||
|
|
||
| it('should push two requests with conflict resolution and replace', () => { |
There was a problem hiding this comment.
I think we should also add a test that queues other unrelated requests and make sure that the replaced request is in the same index as the conflicting ReconnectApp request.
i.e: [OpenReport, AddComment, ReconnectApp, OpenReport]
becomes [OpenReport, AddComment, ReconnectApp, OpenReport], with ReconnectApp still at index 2 for example
|
🧪🧪 Use the links below to test this adhoc build on Android, iOS, Desktop, and Web. Happy testing! 🧪🧪 |
roryabraham
left a comment
There was a problem hiding this comment.
Otherwise I think this prettymuch LGTM 👍🏼
|
@mountiny @roryabraham how is testing going here? |
At this point the PR LGTM, I'm just waiting for @shubham1206agra to review and test |
|
conflicts btw |
| callback: (val) => { | ||
| persistedRequests = val ?? []; | ||
|
|
||
| if (ongoingRequest && persistedRequests.length > 0) { |
There was a problem hiding this comment.
@gedu How did you ensure that this callback is called after other connection callback?
|
Please use this thread to try to wrap this PR up as soon as possible https://expensify.slack.com/archives/C05LX9D6E07/p1727863372595789 |
# Conflicts: # src/libs/Network/SequentialQueue.ts
| Onyx.set(ONYXKEYS.PERSISTED_REQUESTS, requests).then(() => { | ||
|
|
||
| Onyx.multiSet({ | ||
| [ONYXKEYS.PERSISTED_REQUESTS]: persistedRequests, |
There was a problem hiding this comment.
| [ONYXKEYS.PERSISTED_REQUESTS]: persistedRequests, | |
| [ONYXKEYS.PERSISTED_REQUESTS]: requests, |
|
🧪🧪 Use the links below to test this adhoc build on Android, iOS, Desktop, and Web. Happy testing! 🧪🧪 |
Reviewer Checklist
Screenshots/VideosAndroid: NativeAndroid: mWeb ChromeScreen.Recording.2024-10-02.at.7.52.57.PM.moviOS: NativeScreen.Recording.2024-10-02.at.8.08.16.PM.moviOS: mWeb SafariScreen.Recording.2024-10-02.at.7.29.10.PM.movMacOS: Chrome / SafariScreen.Recording.2024-10-02.at.7.21.33.PM.movScreen.Recording.2024-10-02.at.7.22.53.PM.movMacOS: DesktopScreen.Recording.2024-10-02.at.7.57.29.PM.mov |
|
✋ 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 https://github.com/roryabraham in version: 9.0.44-0 🚀
|
|
🚀 Deployed to production by https://github.com/jasperhuangg in version: 9.0.44-12 🚀
|
| throw new Error('No requests to process'); | ||
| } | ||
|
|
||
| ongoingRequest = persistedRequests.shift() ?? null; |
There was a problem hiding this comment.
Coming from #57119 checklist: After shifting persistedRequests, the request still includes the same shifted request in offline mode, like with toggle API requests. When we handle endRequestAndRemoveFromQueue it ends up removing the same shifted request. To handle this case, we need to ensure the request is unique.
Details
we have 4 places that can trigger the ReconnectApp:
so, In the PersistedRequest file, within the save function, I would add a check to see if a ReconnectApp already exists in the persistedRequest queue. If it does, replace it with the new incoming ReconnectApp. This ensures we always maintain just one instance of it, with the most up-to-date information to send.
Fixed Issues
$ #47742
PROPOSAL: #47742 (comment)
Reference: #40059
Tests
Base
With failing requests
Simulate failing network requestsWith failing requests
Force offlineForce offlineOffline tests
QA Steps
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectiontoggleReportand notonIconClick)myBool && <MyComponent />.src/languages/*files and using the translation methodSTYLE.md) were followedAvatar, I verified the components usingAvatarare working as expected)StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))Avataris modified, I verified thatAvataris working as expected in all cases)Designlabel and/or tagged@Expensify/designso the design team can review the changes.ScrollViewcomponent to make it scrollable when more elements are added to the page.mainbranch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTeststeps.Screenshots/Videos
Android: Native
single_reconnectApp_android.mp4
Android: mWeb Chrome
single_reconnectApp_androidWeb.mp4
iOS: Native
single_reconnectApp_ios.mp4
iOS: mWeb Safari
single_reconnectApp_iosWeb.mp4
MacOS: Chrome / Safari
single_reconnectApp_chrome.mp4
single_reconnectApp_safari.mp4
MacOS: Desktop
single_reconnectApp_desktop.mp4