fix(session): wait for a losing logout teardown before re-creating its profile - #999
Merged
Merged
Conversation
…s profile teardownEngineSafely races a teardown against a 10s deadline, but the losing promise keeps running — and logout()'s ends in an fs.rm of the session's on-disk profile, the same deterministic path a later start() re-creates. A pupBrowser.close() wedged past the deadline could land that rm on credentials written by a subsequent pairing. Losing logout() teardowns are now registered in a pendingTeardowns map (self-removing on settlement), and start()/delete() wait (bounded) for them before touching the profile path. A teardown still wedged past the bound no longer blocks the operator; that residual window is logged. Closes #994
rmyndharis
added a commit
that referenced
this pull request
Jul 29, 2026
…the deadline race (#1001) PR #999 added two teardown-resilience tests that drive logout() with a promise hung past the 10s deadline, then await the call assuming it resolves. PR #997 (which landed first) made logout() throw BadGatewayException whenever the unlink is unconfirmed — exactly the outcome of a lost deadline race — so both tests have failed on main since #999 merged on top of it. The production behaviour from #997 is correct and already asserted explicitly (logout() rejects with 502 when the unlink is unconfirmed, but the local teardown still completes). This updates the two #999 tests to expect that rejection, while preserving what they actually exercise: the losing promise stays registered in pendingTeardowns and start() still waits for it (bounded) before re-creating the profile.
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.
Description
Fixes #994 (found reviewing #984; the race predates that PR but only becomes destructive with
logout()in the mix).teardownEngineSafelyraces an engine teardown against a 10s deadline viaPromise.race, but the losing promise keeps running. Fordisconnect()/forceDestroy()that's benign — they never touch disk.logout()is the first teardown that deletes on-disk state (wwjsLocalAuth.logout()→fs.rmof<dataPath>/session-<id>; BaileysclearAuthState()→authDir/sessionId), and both are deterministic paths a subsequentstart()re-creates: apupBrowser.close()wedged past the deadline could land thatrmon credentials written by a fresh pairing.The change:
pendingTeardownsmap, self-removing on settlement with an identity check so a newer teardown's entry isn't evicted by an older one settling. Only'logout'is tracked; the other teardown labels never touch disk.start()waits (bounded, 10s) for a pending teardown to settle beforeinitializeEnginewrites the fresh profile;delete()does the same beforepurgeSessionData. If the teardown is still wedged past the bound, the operator is not blocked indefinitely — the stalermsits behind the wedge — and that residual window is logged (pending_teardown_wait_exhausted).Two new service tests with fake timers:
start()creates no engine while a losing logout teardown is pending and proceeds once it settles (entry self-removes); andstart()proceeds after the bounded wait when the teardown never settles.Type of Change
Checklist
Related Issues
Closes #994