Report web socket connection failures instead of hanging on "Connecting …" - #193
Merged
Merged
Conversation
When the web socket never reaches OPEN the recorder stayed on "Connecting …" indefinitely, with no error and no way for the host application to react. Three causes: - The stream "close" handler expected an error argument, but Node streams never pass one on close, so that branch was dead code. - A socket that closed without ever having connected only triggered a reconnect when user media was already loaded. During the initial connect it never is, so nothing happened at all. - options.timeouts.connection was only honoured for HTTP requests, so a stalled connect had no timeout of its own. Now a socket that closes before connecting emits ERROR naming the socketUrl, and options.timeouts.connection also guards the web socket connect for the case where the connection stalls rather than being refused. Reconnecting after an established connection drops is unchanged.
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
When the web socket never reaches
OPEN, the recorder stays onConnecting …forever. NoERRORis emitted, nothing is logged above debug level, and the host application has no way to react or tell the user anything.This is trivially reproducible: point
socketUrlat a hostname that does not resolve, or at a host that refuses the connection. I hit it running the Videomail app in an Android emulator, where the configured local dev domain only resolves on the host machine.Cause
Three separate things line up to swallow the failure.
1. The
closehandler expected an error argument that never arrives.Node streams (and
duplexify, whichwebsocket-streambuilds on) never pass an argument toclose. Soerris alwaysundefinedand the wholeERRORbranch is dead code.2. The fallback branch cannot fire during the initial connect.
The
else ifonly reconnects whenuserMediaLoadedis true. During the very first connect it never is, because the camera is not loaded until the socket is up. So a socket that dies before connecting hits neither branch and the recorder simply goes quiet.The browser does give us a signal here — a failed handshake fires
errorand thenclosewith code 1006 — butwebsocket-streamrouteserrorintostream.destroy(err), and ourerrorhandler only writes a debug line.3.
options.timeouts.connectionwas never applied to the web socket.It is documented as "in seconds, increase if api is slow" and honoured in
resource.tsfor HTTP, but the web socket connect had no timeout at all. A stalled connect (packets silently dropped rather than refused) fires neithererrornorcloseuntil the OS gives up, which can take minutes.Fix
closeno longer takes a phantom error argument. Instead it records whether the socket ever connected, and reports a failure when it did not. Reconnecting after an established connection drops is unchanged.options.timeouts.connectionnow also guards the web socket connect, covering the stalled case.failConnection()method, guarded so a single attempt emits at most oneERROR, and so it destroys the pending stream rather than leaving it dangling.unload()clears the connection timeout and dropsconnectingbefore destroying the stream, so tearing down a pending connection is not misreported as a failure.The emitted error names the
socketUrlthat was attempted, which makes misconfiguration self-explanatory:Notes
Recorderhas no test harness in this repo (it needsVisuals,Replayand a live DOM), and standing one up is well beyond this fix. Verified manually against an unresolvable host, a refused port and a healthy connection.npm run types,npm run lint,npm run prettierandnpm testall pass.