-
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
fix/15627: Requeue ReconnectApp API requests to fix old data getting rendered when going from offline to online mode #16093
Conversation
826f78e
to
794a51d
Compare
@MonilBhavsar @eVoloshchak One of you needs to 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] |
@tienifr, there's a bug when updating the profile picture, the image is flickering multiple times Screen.Recording.2023-03-21.at.13.25.01.movI also noticed image flickerning when changing workspace avatar (but for a plit-second), I suppose that's the local url being replaced with a remote url, but the remote image needs some time to load, during which the image is greyed-out, thus the flickering. Screen.Recording.2023-03-21.at.12.56.09.mov |
@eVoloshchak Yes, I can see the image is flickering multiple times, but it happens even on staging and it's not related to this PR. Should we handle it in other PR? Thanks |
Yeah, this should be handled as a separate issue then. Could you report this in #expensify-bugs please? |
Yes |
@eVoloshchak Done all your comments, thanks |
There's a couple left |
Yes, my fault, I've updated my PR |
Reviewer Checklist
Screenshots/VideosWebScreen.Recording.2023-03-21.at.22.37.00.movMobile Web - ChromeScreen_Recording_20230321-224831_Chrome.mp4Mobile Web - SafariScreen.Recording.2023-03-21.at.22.39.32.movDesktopScreen.Recording.2023-03-21.at.22.35.40.moviOSIMG_0009.MP4AndroidScreen_Recording_20230321-224950_New.Expensify.mp4 |
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.
Looks good and tests well
cc: @MonilBhavsar
@MonilBhavsar Do we proceed this one? |
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.
Code looks good to me. Testing now
@MonilBhavsar how it's going? |
Sorry for delay, I had issues with my VM. Will get back to this |
I would also suggest making PR title to somewhat general like - "Requeue ReconnectApp API requests to fix old data getting rendered when going from offline to online mode" |
@MonilBhavsar I just updated the PR title |
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!
Works fine! Let's see 🤞
✋ 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/MonilBhavsar in version: 1.2.89-0 🚀
|
🚀 Deployed to production by https://github.com/luacmartins in version: 1.2.89-0 🚀
|
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.
Hey I'm just passing through here as this PR popped up on my radar as being kind of suspect...
I could be misunderstanding this - but in general, I think we should not be modifying the contents of persisted requests in the write queue. If there is some problem related to concurrency of request data then it feels like a possible bandaid approach to remove the "problematic" command.
Let me know if my interpretation is off here.
@@ -21,6 +21,9 @@ Onyx.connect({ | |||
// We use the AbortController API to terminate pending request in `cancelPendingRequests` | |||
let cancellationController = new AbortController(); | |||
|
|||
// To terminate pending ReconnectApp requests https://github.com/Expensify/App/issues/15627 |
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.
Please do not leave links to issues in the code. If someone needs to figure out where and why this was added they can use git blame.
.concat(requestsToPersist) | ||
.partition(request => request.command !== CONST.NETWORK.COMMAND.RECONNECT_APP) | ||
.flatten() | ||
.value(); |
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 exactly is happening here? 🤔
Is the goal to move the ReconnectApp
calls to a different order? Why are we doing it this?
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.
You may need to take a look at the PR details or my linked proposal here #15627 to get the context.
Is the goal to move the ReconnectApp calls to a different order?
Yes, the goal is to re-order ReconnectApp
to always fire last.
Why?
Whenever we switch from offline to online, ReconnectApp
request is fired to retrieve the latest updates while we're offline (new messages, pending IOU,...). Prior to this PR, ReconnectApp
is fired first regardless of any pending update requests:
- The update action is made, the component is updated with optimistic data
ReconnectApp
retrieves the old data (data before the update), the component is updated as the old data- Update request retrieves the updated data, the component is updated as the success data
This causes the component to flicker between optimistic, old and success data. Thus, I think the correct flow is to update first then ReconnectApp
.
Note that if we do this, the order of other requests will remain the same.
For example:
A > B > ReconnectApp > C
to
A > B > C > ReconnectApp
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 - probably no way for you to know this - but the changes violate a basic principle of how the network layer is supposed to work (i.e. "write" requests happen in the order they are triggered). Reordering this call might "fix" the issue - but it doesn't make it the "correct flow". I think we're going to discuss internally how to solve this appropriately, thanks!
return processHTTPRequest(url, type, formData, data.canCancel, command); | ||
} | ||
|
||
function cancelPendingReconnectAppRequest() { |
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.
Why does this need it's own cancel controller?
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.
In some edge cases where we cannot re-order the ReconnectApp
requests we should cancel them and re-queue them later. Basically the idea is to make sure ReconnectApp
always fires last.
For example if the update action was made immediately after switching online (i.e. ReconnectApp
has already been fired but not completed yet).
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 make sure ReconnectApp always fires last
Yeah, again, it feels like we are making a weird exceptional case for ReconnectApp
. IMO, there should be nothing special about ReconnectApp
. The perception that it needs to "happen last" is entirely related to the data that it's returning. This change should have been held on a wider conversation with the team. It's sort of clear to me that the network layer isn't perfect and can't handle every edge case. But feels like we are hacking around a deficiency by breaking some core assumptions about how things work.
Heads up I'm reverting these changes and reopening this issue. The hack we used here is blocking a critical performance feature. |
Details
Updating the workspace avatar while offline and then going online after that will switch the avatar to the previous one for a few seconds. This is also happens to other fields: profile picture, display name, pronouns,...
This PR:
Fixed Issues
$ #15627
$ #15627 (comment)
Tests
Edge case:
As a data synchronization issue on offline/online switch, it also impacts other fields: profile picture, display name, pronouns,...
Offline tests
Same above
QA Steps
Edge case:
As a data synchronization issue on offline/online switch, it also impacts other fields: profile picture, display name, pronouns,...
PR Author Checklist
### Fixed Issues
section aboveTests
sectionOffline steps
sectionQA steps
sectiontoggleReport
and notonIconClick
)src/languages/*
files and using the translation methodWaiting for Copy
label for a copy review on the original GH to get the correct copy.STYLE.md
) were followedAvatar
, I verified the components usingAvatar
are working as expected)/** comment above it */
this
properly so there are no scoping issues (i.e. foronClick={this.submit}
the methodthis.submit
should be bound tothis
in the constructor)this
are necessary to be bound (i.e. avoidthis.submit = this.submit.bind(this);
ifthis.submit
is never passed to a component event handler likeonClick
)StyleUtils.getBackgroundAndBorderStyle(themeColors.componentBG
)Avatar
is modified, I verified thatAvatar
is working as expected in all cases)ScrollView
component to make it scrollable when more elements are added to the page.main
branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTest
steps.Screenshots/Videos
Web
Screencast.from.18-03-2023.16.03.46.webm
Mobile Web - Chrome
chrome15627.mp4
Mobile Web - Safari
safari15627.mp4
Desktop
desktop15627.mp4
iOS
ios15627.mp4
Android
Screen.Recording.2023-03-19.at.14.26.34.1.mp4