VAPI-3917 fix(signaling): only retry on close code 1001, tear down on everything else - #19
Merged
Merged
Conversation
…g else rpc-websockets' unlimited auto-reconnect only special-cases close code 1000 - every other code, including ones this SDK doesn't recognize yet, was silently retried forever. Flip the default: 1001 (Going Away) is the only code the gateway sends to mean "come back on this session"; everything else - 1000 (endpoint gone), 4409 (superseded by a newer connection from this same device, pv-gateway PR pv-gateway#123), 1011 (internal error, where the right recovery is minting a new endpoint, not retrying this connection), and any future/unknown code - now disables auto-reconnect and tears the connection down. The gateway-initiated codes (4409, 1011) race the "close" event: the underlying client schedules its reconnect timer synchronously inside the raw WebSocket's own close listener, before it defers emitting the "close" event this file listens on. setAutoReconnect(false) alone is too late for those; the already-queued reconnect_timer_id has to be cleared directly. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
Drop pv-gateway internal implementation detail (drain eviction, media server loss, etc.) from comments — this is a public SDK, comments should describe SDK behavior, not the internals of one server that happens to implement the protocol. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
stampercasey
approved these changes
Sep 9, 2026
stampercasey
added a commit
that referenced
this pull request
Sep 10, 2026
…w retry-code policy origin/main (VAPI-3917, #19) narrowed rpc-websockets' auto-reconnect to close code 1001 only, tearing down on 1000/4409/1011/unknown instead of retrying them forever. That is a different layer than this branch touches - it decides whether the underlying client reconnects at all, while republishStreams() only runs once it has and "init" re-fires - and the two coexist without overlap: FATAL_HANDSHAKE_ERRORS/fatalError fires on a rejected upgrade before any socket exists, RETRY_CLOSE_CODES fires on a close after a successful one. pv-gateway sends 1001 (Going Away) for every retryable teardown (drain eviction, media-server loss, instance shutdown), so it stays in RETRY_CLOSE_CODES and this branch's fix keeps firing on exactly the paths it was built for. Co-Authored-By: Claude Sonnet 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.
Jira: VAPI-3802
The problem
rpc-websocketsis built with unlimited auto-reconnect. Its own internal check only special-cases close code 1000 — every other code, including ones this SDK has never heard of, gets retried forever. A server can legitimately want to reject a reconnect permanently with some other close code, and today's client would just keep hammering it.The fix
Flip the default from a deny-list to an allow-list. 1001 (Going Away) is the only code that means "come back on this exact session." Every other code — 1000 (session over for good), 1011 (internal error, where retrying this same connection isn't the right recovery), 4409, and anything unrecognized — now disables auto-reconnect and tears the connection down instead of silently retrying.
Disabling auto-reconnect alone isn't enough for codes other than 1000:
rpc-websocketsdecides whether to schedule a reconnect synchronously, inside the raw WebSocket's owncloselistener, before it even fires thecloseevent this file listens on (that emit is deferred). By the time our handler runs, the reconnect timer is already queued, so it's cleared directly via the client'sreconnect_timer_id.Test plan
tsc --noEmitcleanjest— 155/155 pass, including new cases for 1001 (retries) and 4409/1011/an unrecognized code (all tear down and disable auto-reconnect)🤖 Generated with Claude Code