fix: disconnect() tears down locally after sending the Leave instead of waiting for the server echo - #1208
Draft
hiroshihorie wants to merge 2 commits into
Draft
fix: disconnect() tears down locally after sending the Leave instead of waiting for the server echo#1208hiroshihorie wants to merge 2 commits into
hiroshihorie wants to merge 2 commits into
Conversation
…echoing the leave engine.disconnect() sends the Leave and relies on the server's echo to run cleanup and emit EngineDisconnectedEvent. Media nodes drop queued leave messages when they close the signal sink, so the echo can be lost. The socket close was then ignored because _isClosed was set, and Room.disconnect() waited out its 10 s timeout for an event that never came, leaving the room half torn down. The engine now remembers a disconnect that is waiting for its echo and, on a socket close in that window, runs cleanup and emits the event itself. A close that follows the echo is still ignored, so there is no second event.
…of waiting for the echo The engine used to send the Leave and rely on the server's echo to run cleanup and emit EngineDisconnectedEvent, and Room.disconnect() waited up to 10 s for that event. Media nodes drop queued leave messages when they close the signal sink, so the echo can be lost, and every lost echo was a 10 s stall, a TimeoutException, and a room left half torn down. No other SDK waits on the server here. disconnect() now sends the Leave, runs cleanUp() and emits the event in one go, like JS, Swift, Android and Rust. A Leave that arrives after disconnect() started is the echo and is ignored. Room.disconnect() owns the teardown for the disconnect it started, so the engine event handler skips its own cleanup in that case and a connect() right after disconnect() returns cannot race it. Replaces the earlier socket close fallback on this branch.
Member
Author
|
e2e-flutter suite (livekit/e2e-flutter#7) against this branch, local livekit-server 1.13.6, macOS, three full runs on 2026-09-16:
ParticipantAttributesTest, the scenario whose agent hit the lost Leave echo on every run before, completed its teardown in about 0.5 s on all three runs with no warning. The 10 skips are camera scenarios, not runnable on this machine. |
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
engine.disconnect()sent the Leave and relied on the server's echo to run cleanup and emitEngineDisconnectedEvent, andRoom.disconnect()waited up to 10 s for that event. Media nodes drop queued leave messages when they close the signal sink (pkg/routing/signal.go,signalMessageSink.Close, comment in place), so the echo can be lost. Every lost echo was a 10 s stall, aTimeoutExceptionout ofdisconnect(), and a room left half torn down becauseRoom.disconnect()never reached its own cleanup.Found by the e2e-flutter suite (livekit/e2e-flutter#7): one agent per run against a local livekit-server 1.13.6,
SignalClient did disconnectwith noLeave receivedbefore it while the server loggedsendLeave: true.This design dates from the Dec 2023 engine rewrite (v1.5.5). #559 (v2.2.2, issue #553) made
Room.disconnect()wait for the event, which turned a silently missing event into a visible stall. No other SDK waits on the server here: JS, Swift, Android and Rust all send the Leave and tear down locally.Fix
Flutter now does the same.
engine.disconnect()sends the Leave, runscleanUp()and emitsEngineDisconnectedEventin one go. No dependency on the echo.disconnect()started is the echo, or a server Leave racing ours, and is ignored.Room.disconnect()awaits the engine teardown and then its own cleanup, no wait on the server and no timeout. The engine event handler skips its cleanup whileRoom.disconnect()is running, so teardown has one owner and aconnect()right afterdisconnect()returns cannot race a straggling handler. That is the case behind [bug] Actions stop working after second connect attempt to same room flutter livekit client #553, now covered by a test.The first commit on this branch was a narrower fallback that completed the disconnect on socket close while keeping the echo dependency. The second commit replaces it with the alignment above.
Tests
test/core/disconnect_event_test.dart, four added:disconnect()with oneclientInitiatedeventdisconnect()returns with engine and room torn down when the server sends nothing at alldisconnect()returnsThe last two fail on main. Full suite 428 passing.
Not yet run
The e2e-flutter suite against this branch. The fallback version of the branch turned the suite's one warning into zero and cut the run by 9 s. Xcode is not available on my machine at the moment, so the final version has not had its real-server run yet. Will report here when it has.
🤖 Generated with Claude Code