fix(client): automatically reconnect to the voice plugin after websocket close - #161
Open
ElektroHeld wants to merge 1 commit into
Open
fix(client): automatically reconnect to the voice plugin after websocket close#161ElektroHeld wants to merge 1 commit into
ElektroHeld wants to merge 1 commit into
Conversation
Contributor
|
|
Overall Grade |
Security Reliability Complexity Hygiene |
Code Review Summary
| Analyzer | Status | Updated (UTC) | Details |
|---|---|---|---|
| Secrets | Jul 21, 2026 10:31p.m. | Review ↗ | |
| JavaScript | Jul 21, 2026 10:31p.m. | Review ↗ |
Important
AI Review is run only on demand for your team. We're only showing results of static analysis review right now. To trigger AI Review, comment @deepsourcebot review on this thread.
…ket close Previously, when the NUI websocket connection to the local voice plugin was lost (plugin crash, TS/Mumble connection drop, etc.), the client only logged the disconnect and set the plugin state to NOT_CONNECTED. Nothing ever called websocket.start() again, so the player stayed stuck in a disconnected state until the whole game client was restarted. Add scheduleReconnect(), which retries websocket.start() with exponential backoff (capped at 30s, up to 10 attempts) whenever the websocket closes, and resets the attempt counter once it reopens. This reuses the existing server-side playerReconnect()/wsReady flow that was already in place but unreachable without a fresh open event.
ElektroHeld
force-pushed
the
fix/websocket-auto-reconnect
branch
from
July 21, 2026 22:31
b296c33 to
0bf0608
Compare
ElektroHeld
marked this pull request as ready for review
July 21, 2026 23:00
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
Some players occasionally get stuck after the websocket connection between the FiveM client resource and the local YaCA voice plugin drops (plugin crash, TS/Mumble connection loss, etc.). The only way for them to recover was to fully restart the game and rejoin the server.
Root cause
In
apps/yaca-client/src/yaca/main.ts, theclient:yaca:inithandler only ever callswebsocket.start()once, inside anif (!this.websocket.initialized)guard.initializedis set totrueon the first successful connect and never reset. Thecloseevent handler only logs the disconnect and sets the plugin state toNOT_CONNECTED— it never triggers a newstart()call.Since
websocket.initializedstaystrueforever, that guard can never run again, so nothing re-establishes the connection. Any subsequentclient:yaca:initfrom the server falls through toinitRequest(), which callswebsocket.send()— a no-op oncereadyState !== 1. TherangeIntervalalso keeps firing every 250ms sending doomed no-op writes. The server-side reconnect path (playerReconnect()viaserver:yaca:wsReady) already exists but is unreachable, since it depends on the client'sopenevent firing again, which never happens.Fix
Add a
scheduleReconnect()method that:websocket.start()with exponential backoff (1s, 2s, 4s, ... capped at 30s), up to 10 attempts.closehandler.openevent fires again.connect_errorlocale string if all retries are exhausted.This reuses the existing (previously unreachable) server-side
playerReconnect()/wsReadyflow rather than duplicating the init logic — oncewebsocket.start()succeeds again, the existingopenhandler already does the right thing (re-sendsINITon first connect, or emitsserver:yaca:wsReadyfor the server to re-sync the player).Testing
pnpm run typecheck— passespnpm biome check— passespnpm run build— passes (client + server build successfully)Notes
I don't have push access to this repo, so I opened this from a fork. Let me know if you'd like a different approach (e.g. unlimited retries, different backoff shape, or resetting
websocket.initializedinstead of adding a dedicated reconnect path).