Fix re-login hang on auth page after logout#5535
Draft
FadhlanR wants to merge 2 commits into
Draft
Conversation
…tate) MatrixService is a singleton whose client-ready barrier (#clientReadyDeferred) was only ever fulfilled once, at boot in loadSDK(). Logout stays in-app (a router transition, not a page reload) and its finally runs resetState(), which recreates the client synchronously but then replaced #clientReadyDeferred with a fresh, never-fulfilled Deferred. The next login awaits that deferred in createRealmSession(), so it never resolves and the auth page hangs. Fulfill the freshly created deferred when _client exists, restoring the invariant "the deferred is fulfilled whenever _client exists" while keeping the memory-cleanup intent of a stale-reference-free deferred. Add an integration regression test covering re-login after a resetState(). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contributor
Preview deploymentsHost Test Results 1 files ±0 1 suites ±0 2h 40m 27s ⏱️ -9s Results for commit 730b3df. ± Comparison against earlier commit 12d188b. Realm Server Test Results 1 files ±0 1 suites ±0 17m 14s ⏱️ +30s Results for commit 730b3df. ± Comparison against earlier commit 12d188b. |
resetState() now leaves the client-ready barrier untouched instead of recreating and immediately fulfilling it — a once-fulfilled deferred stays fulfilled, and the reset recreates the client synchronously whenever the SDK is loaded, so the two are equivalent. The new matrix E2E test covers the full in-app logout -> login-form -> re-login flow that the host integration test can't: logout is a router transition, not a page reload, so the second login runs against the client that resetState() recreated. The test waits for logout's transition to index-root before filling the form, since that transition remounts the login form and would wipe an earlier fill. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.
Problem
After logging out, the next in-app login (any method) hangs indefinitely on the auth page: the form submits but never progresses. Reliably reproduced via Google SSO → logout → email/password login → stuck, but the root cause is not SSO-specific — any logout → in-app re-login (without a page reload) hits it.
Root cause
MatrixServiceis a singleton. Its client-ready barrier#clientReadyDeferredis only ever fulfilled once, at boot insideloadSDK()— the sole call site of.fulfill().Logout stays in-app (
router.transitionTo, not a page reload), and itsfinallyrunsresetState().resetState()recreates the matrix client synchronously but then replaces#clientReadyDeferredwith a fresh, never-fulfilledDeferred. Nothing re-runsloadSDK(), so the new deferred stays pending for the life of the singleton.The next login → realm auth →
createRealmSession()doesawait this.#clientReadyDeferred.promise. That promise never resolves →start()never returns → the login task never settles → the auth page stays mounted.Regression introduced in
f3fb792bce("Memory leak cleanup"): before it,resetState()left the deferred fulfilled. The cleanup recreated it to drop references but overlooked that it is only fulfilled once, at boot.Fix
In
resetState(), fulfill the freshly created#clientReadyDeferredwhen_clientexists (the client is already recreated synchronously just above). This restores the invariant "the deferred is fulfilled whenever_clientexists" while keeping the memory-cleanup intent of a stale-reference-free deferred. The_clientguard covers the edge case where the SDK hasn't loaded yet.Testing
New integration test
matrix-service-relogin-test.tsassertscreateRealmSessionsettles after aresetState()instead of hanging (raced against a timeout guard so a hang fails the test rather than stalling the suite).Verified headless:
matrix-serviceintegration filter is green (22/22).🤖 Generated with Claude Code