Summary
PlaywrightTunnel.stopAsync() can hang when the tunnel is stopped while it is still waiting for a poll-connection client to arrive.
Why this is a separate issue
The current PR (#5851) fixes a Start/Stop lifecycle race by waiting for an in-progress stop before starting again. That does not address the case where Stop itself never settles while the tunnel is still in waiting-for-connection / poll-connection mode.
Suspected root cause
In poll-connection mode, _pollConnectionAsync() returns a promise that only resolves after a WebSocket connection succeeds. stopAsync() clears the polling interval, but it still awaits _initWsPromise, which can remain unresolved forever if Stop happens before a connection arrives.
Proposed fix shape
- Add a cancellation/settle path for the pending poll promise when stopping.
- Ensure
stopAsync() can complete even if no WebSocket ever connected.
- Clear any pending poll state and set status to stopped as part of stop teardown.
Evidence
A local gws auth login flow now reaches a clean timeout when the VS Code extension never connects, which suggests the remaining stall is in the extension stop path rather than the remote side.
Summary
PlaywrightTunnel.stopAsync()can hang when the tunnel is stopped while it is still waiting for a poll-connection client to arrive.Why this is a separate issue
The current PR (#5851) fixes a Start/Stop lifecycle race by waiting for an in-progress stop before starting again. That does not address the case where Stop itself never settles while the tunnel is still in
waiting-for-connection/ poll-connection mode.Suspected root cause
In poll-connection mode,
_pollConnectionAsync()returns a promise that only resolves after a WebSocket connection succeeds.stopAsync()clears the polling interval, but it still awaits_initWsPromise, which can remain unresolved forever if Stop happens before a connection arrives.Proposed fix shape
stopAsync()can complete even if no WebSocket ever connected.Evidence
A local
gws auth loginflow now reaches a clean timeout when the VS Code extension never connects, which suggests the remaining stall is in the extension stop path rather than the remote side.