Real-time collaboration: Remove ghost awareness state explicitly when refreshing#75883
Conversation
|
This feels related to #75829. @alecgeatches What do you think about using
Do we want to hide presence indicators when the user is not actively "in" the session? |
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
@chriszarate I think this might be a step too far. As quoted above,
This might make sense in a mobile-only context where switching tabs is more similar to exiting the session, but on a desktop I wouldn't expect switching tabs and minimizing to be a place where a user's session data is removed. This is also a bit simpler - we can fire and forget and don't need to worry about reinitializing a user if the tab is resumed. |
| const payload: SyncPayload = { | ||
| rooms: rooms.map( ( { room, clientId } ) => ( { | ||
| after: 0, | ||
| awareness: null, | ||
| client_id: clientId, | ||
| room, | ||
| updates: [], | ||
| } ) ), | ||
| }; |
There was a problem hiding this comment.
Nitpick, but I'd rather see the parameters of these functions be consistent and accept SyncPayload[]. This mapping can be done in the calling code.
There was a problem hiding this comment.
Good idea! Removed sendDisconnect() in 7b1131b and added a non-blocking version of postSyncUpdate to call since it's essentially the same thing.
…nc payload in caller
|
I have created a backport PR for core here: WordPress/wordpress-develop#11049 |
… refreshing (#75883) * Explicitly send a null awareness state on pagehide to remove stale cursors * Add postSyncUpdateNonBlocking instead of sendDisconnect, construct sync payload in caller * Add backport changelog file Co-authored-by: alecgeatches <alecgeatches@git.wordpress.org> Co-authored-by: chriszarate <czarate@git.wordpress.org>
|
I just cherry-picked this PR to the wp/7.0 branch to get it included in the next release: 17eeb51 |
… refreshing. Syncs PHP changes from WordPress/gutenberg#75883. Changes the real-time collaboration polling server endpoint to accept null for awareness values, which is used to explicitly disconnect users leaving the page and remove their awareness data more quickly. CI run: #11049. Fixes #64622. Props alecgeatches. git-svn-id: https://develop.svn.wordpress.org/trunk@61746 602fd350-edb4-49c9-b593-d223f7449a82
… refreshing. Syncs PHP changes from WordPress/gutenberg#75883. Changes the real-time collaboration polling server endpoint to accept null for awareness values, which is used to explicitly disconnect users leaving the page and remove their awareness data more quickly. CI run: WordPress/wordpress-develop#11049. Fixes #64622. Props alecgeatches. Built from https://develop.svn.wordpress.org/trunk@61746 git-svn-id: http://core.svn.wordpress.org/trunk@61052 1a063a9b-81f0-0310-95a4-ce76da25c4cd
CI run: #11059. See #64595. --- I've included a log of the Gutenberg changes with the following command: git log --reverse --format="- %s" 23b566c72e9c4a36219ef5d6e62890f05551f6cb..022d8dd3d461f91b15c1f0410649d3ebb027207f | sed 's|#\([0-9][0-9]*\)|https://github.com/WordPress/gutenberg/pull/\1|g; /github\.com\/WordPress\/gutenberg\/pull/!d' | pbcopy - Pattern Editing: Fix nested patterns/sections (WordPress/gutenberg#75772) - QuickEdit: rename status label and remove extra labels in popup (WordPress/gutenberg#75824) - Fix block editing modes not recomputing when isolated editor value changes (WordPress/gutenberg#75821) - Synced patterns: Fix block editing mode of synced pattern content when nested in an unsynced pattern (WordPress/gutenberg#75818) - Block Support: Fix custom CSS not saved when style schema is not defined (WordPress/gutenberg#75797) - Gallery: Fixes keyboard focus escaping the lightbox overlay when navigating a gallery with Tab/Shift+Tab. (WordPress/gutenberg#75852) - Navigation Overlay Close: Set Close as default text, rather than using a placeholder (WordPress/gutenberg#75692) - RTC: Fix entity save call / initial persistence. (WordPress/gutenberg#75841) - Real-time collaboration: Improve collaboration within the same rich text (WordPress/gutenberg#75703) - Client Side Media: Add device/browser capability detection (WordPress/gutenberg#75863) - Navigation editing: simplify edit/view buttons (WordPress/gutenberg#75819) - Add core/icon block to theme.json schema (WordPress/gutenberg#75813) - Fix error when undoing newly added pattern (WordPress/gutenberg#75850) - Page List Item: Replace RawHTML with dangerouslySetInnerHTML for label and title (WordPress/gutenberg#75890) - REST API: Make filter_wp_unique_filename() static to match core, plus avoid duplicate routes (WordPress/gutenberg#75782) - RichText: useAnchor: Fix TypeError in virtual element (WordPress/gutenberg#75900) - DataViews: Remove menu divider again. (WordPress/gutenberg#75908) - Theme: Add build plugins to inject design token fallbacks (WordPress/gutenberg#75901) - Theme: Remove global stylesheet (WordPress/gutenberg#75879) - Real-time collaboration: Remove ghost awareness state explicitly when refreshing (WordPress/gutenberg#75883) - Real-time collaboration: Expand mergeCrdtBlocks() automated testing (WordPress/gutenberg#75923) - Fix client-side media file naming (WordPress/gutenberg#75817) - Add: Connectors screen (WordPress/gutenberg#75833) - Merge document meta into state map (WordPress/gutenberg#75830) - Move WordPress meta key from sync package to core-data (WordPress/gutenberg#75846) - Bugfix: Fix casing of getPersistedCRDTDoc (WordPress/gutenberg#75922) - Add debug logging to SyncManager (WordPress/gutenberg#75924) - DataForm: fix label colors (WordPress/gutenberg#75730) - DataViews: minimize padding for primary action buttons (WordPress/gutenberg#75721) (WordPress/gutenberg#75947) - Connectors: Add `_ai_` prefix to connector setting names and fix naming inconsistencies (WordPress/gutenberg#75948) - Connectors: Unhook Core callbacks in Gutenberg coexistence (WordPress/gutenberg#75935) - Unsynced patterns: Rename 'Disconnect pattern' to 'Detach pattern' in context menu (WordPress/gutenberg#75807) - Editor: Remove View dropdown and pinned items from revisions header (WordPress/gutenberg#75951) - Fix: Template revisions infinite spinner (WordPress/gutenberg#75953) - Backport: Avoid flickering while refreshing (WordPress/gutenberg#74572) (WordPress/gutenberg#75952) - Add wp_ prefix to real time collaberation option. (WordPress/gutenberg#75837) git-svn-id: https://develop.svn.wordpress.org/trunk@61750 602fd350-edb4-49c9-b593-d223f7449a82
CI run: WordPress/wordpress-develop#11059. See #64595. --- I've included a log of the Gutenberg changes with the following command: git log --reverse --format="- %s" 23b566c72e9c4a36219ef5d6e62890f05551f6cb..022d8dd3d461f91b15c1f0410649d3ebb027207f | sed 's|#\([0-9][0-9]*\)|https://github.com/WordPress/gutenberg/pull/\1|g; /github\.com\/WordPress\/gutenberg\/pull/!d' | pbcopy - Pattern Editing: Fix nested patterns/sections (WordPress/gutenberg#75772) - QuickEdit: rename status label and remove extra labels in popup (WordPress/gutenberg#75824) - Fix block editing modes not recomputing when isolated editor value changes (WordPress/gutenberg#75821) - Synced patterns: Fix block editing mode of synced pattern content when nested in an unsynced pattern (WordPress/gutenberg#75818) - Block Support: Fix custom CSS not saved when style schema is not defined (WordPress/gutenberg#75797) - Gallery: Fixes keyboard focus escaping the lightbox overlay when navigating a gallery with Tab/Shift+Tab. (WordPress/gutenberg#75852) - Navigation Overlay Close: Set Close as default text, rather than using a placeholder (WordPress/gutenberg#75692) - RTC: Fix entity save call / initial persistence. (WordPress/gutenberg#75841) - Real-time collaboration: Improve collaboration within the same rich text (WordPress/gutenberg#75703) - Client Side Media: Add device/browser capability detection (WordPress/gutenberg#75863) - Navigation editing: simplify edit/view buttons (WordPress/gutenberg#75819) - Add core/icon block to theme.json schema (WordPress/gutenberg#75813) - Fix error when undoing newly added pattern (WordPress/gutenberg#75850) - Page List Item: Replace RawHTML with dangerouslySetInnerHTML for label and title (WordPress/gutenberg#75890) - REST API: Make filter_wp_unique_filename() static to match core, plus avoid duplicate routes (WordPress/gutenberg#75782) - RichText: useAnchor: Fix TypeError in virtual element (WordPress/gutenberg#75900) - DataViews: Remove menu divider again. (WordPress/gutenberg#75908) - Theme: Add build plugins to inject design token fallbacks (WordPress/gutenberg#75901) - Theme: Remove global stylesheet (WordPress/gutenberg#75879) - Real-time collaboration: Remove ghost awareness state explicitly when refreshing (WordPress/gutenberg#75883) - Real-time collaboration: Expand mergeCrdtBlocks() automated testing (WordPress/gutenberg#75923) - Fix client-side media file naming (WordPress/gutenberg#75817) - Add: Connectors screen (WordPress/gutenberg#75833) - Merge document meta into state map (WordPress/gutenberg#75830) - Move WordPress meta key from sync package to core-data (WordPress/gutenberg#75846) - Bugfix: Fix casing of getPersistedCRDTDoc (WordPress/gutenberg#75922) - Add debug logging to SyncManager (WordPress/gutenberg#75924) - DataForm: fix label colors (WordPress/gutenberg#75730) - DataViews: minimize padding for primary action buttons (WordPress/gutenberg#75721) (WordPress/gutenberg#75947) - Connectors: Add `_ai_` prefix to connector setting names and fix naming inconsistencies (WordPress/gutenberg#75948) - Connectors: Unhook Core callbacks in Gutenberg coexistence (WordPress/gutenberg#75935) - Unsynced patterns: Rename 'Disconnect pattern' to 'Detach pattern' in context menu (WordPress/gutenberg#75807) - Editor: Remove View dropdown and pinned items from revisions header (WordPress/gutenberg#75951) - Fix: Template revisions infinite spinner (WordPress/gutenberg#75953) - Backport: Avoid flickering while refreshing (WordPress/gutenberg#74572) (WordPress/gutenberg#75952) - Add wp_ prefix to real time collaberation option. (WordPress/gutenberg#75837) Built from https://develop.svn.wordpress.org/trunk@61750 git-svn-id: http://core.svn.wordpress.org/trunk@61056 1a063a9b-81f0-0310-95a4-ce76da25c4cd
What?
This PR explicitly disconnects users from awareness when the page is refreshed or otherwise navigated using the browser
pagehideevent.Why?
When refreshing the page in real-time collaboration, the previous session's cursor stays around for a while. This can lead to confusion from ghost collaborators from the same user and have a negative visual impact:
Screen.Recording.2026-02-24.at.12.17.29.PM.mov
Clicking into a post and refreshing quickly creates several ghost users and cursors in
trunkHow?
This PR explicitly sends a disconnect signal (
nullawareness update) onpagehide. From MDN:The documentation above notes that this behavior works differently on mobile, but only in the way that it will NOT be explicitly fired if a user force-closes a browser in the background. This is fine, since awareness state will automatically be cleared out after a 30-second interval anyway.
We also
apiFetch()with thekeepalive: trueoption, which according to documentation:The naming is a bit confusing but
keepalive: truemeans the disconnect request can finish independent of the current page, so it's non-blocking to a refresh or navigation.Testing Instructions
Screenshots
Here is the same demo as above but performed within this PR:
refresh-cursors-fixed.mov
I've also included a second user to see what this looks like to a third-party observer watching the same post.
Above we can see that user A (the left-hand side) never sees their cursor reappear, as their awareness data is removed during the refresh and no longer present after loading. User B has a short grace period for ghost cursors (5 seconds) before duplicate cursors are removed. This could be further improved but is relatively minor.