fix: block y-websocket auto-reconnect during async IMS refresh#943
Merged
Conversation
|
Hello, I'm the AEM Code Sync Bot and I will run some actions to deploy your branch.
Commits
|
The 4401 close handler awaits adobeIMS.refreshToken() before deciding whether to retry. y-websocket's onclose schedules its own setTimeout(setupWS, ...) synchronously; on a 4401 the upgrade returned 101 + immediate close, so onopen briefly fired and wsUnsuccessfulReconnects stayed at 0 - backoff is 2^0*100=100ms, shorter than a typical IMS refresh round-trip. The auto-reconnect fired with the still-stale token and burned 2-3 HEAD 401s on da-admin per token expiry per tab. Flip provider.shouldConnect=false synchronously before the first await so the pending setTimeout becomes a no-op, then drive the reconnect ourselves via provider.connect() once we have the fresh token. Same fix removes the bug 2 race where two concurrent close handlers could mutate lastSentToken out from under each other and stop reconnection on a successful refresh. Also skip the createAwarenessStatusWidget checkDoc HEAD on auth-close codes - those signal auth failure not doc-deleted, and the daFetch refresh-and-retry doubles the HEAD 401 traffic for no benefit. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
auniverseaway
approved these changes
May 18, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Why
Three remaining bugs around the IMS token refresh path that survived #937 / #941. Together they explain a continuous baseline of HEAD 401s on da-admin (660k/day in Coralogix) even after those PRs landed.
Bug 1 — Race between async refresh and y-websocket's 100ms reconnect timer
y-websocket'soncloseschedulessetTimeout(setupWS, 2^wsUnsuccessfulReconnects * 100ms)synchronously. On a4401close the upgrade returns101+ immediate close, soonopenbriefly fires andwsUnsuccessfulReconnectsstays at0— backoff is 100ms, shorter than a typicaladobeIMS.refreshToken()round-trip. The auto-reconnect fired with the still-stale token and burned 2–3 HEAD 401s on da-admin per token expiry per tab.Bug 2 — Concurrent close handlers racing
lastSentTokenBecause bug 1 produced multiple 4401 closes back-to-back, multiple async handlers ran concurrently. Handler A finishes first and writes
lastSentToken = X2. Handler B (started during A's await) then seesfresh === lastSentToken(X2 === X2) and incorrectly concludes "no new token", setsshouldConnect = false, and shows the auth banner — even though the refresh worked.Bug 3 —
checkDocdoubles the HEAD volume on auth-closecreateAwarenessStatusWidgethas a secondconnection-closelistener that callscheckDoc(path)→daFetch(path, { method: 'HEAD' })on every close. On a 4401/4403 the doc is fine — da-collab signalled an auth failure — so this just fires another HEAD on da-admin whichdaFetch's refresh-and-retry compounds further.What
shouldConnect=falsesynchronously before the first await in the close handler. The pendingsetTimeout(setupWS)becomes a no-op, eliminating bugs 1 and 2 (no concurrent close handlers because no auto-reconnects fire during the refresh window).provider.connect()once we have the fresh token.checkDocwhen the close code is4401/4403.Trust model
Unchanged.
4403still stops reconnection.4401with no new token still bails and surfaces the modal. Anonymous users still bail without showing the modal.Tests
Blocks y-websocket auto-reconnect during the in-flight refresh on 4401— controlsrefreshTokenvia an unresolved promise and assertsshouldConnect===falseduring the await, thentrueafter.Skips checkDoc HEAD on auth-close codes (4401/4403)— patcheswindow.fetchand asserts no HEAD is issued on 4401/4403, but is on 1006.🤖 Generated with Claude Code