Skip to content

Fix unpublish_track deadlock on FFI error - #752

Open
apoorva-01 wants to merge 1 commit into
livekit:mainfrom
apoorva-01:fix/565-unpublish-deadlock
Open

Fix unpublish_track deadlock on FFI error#752
apoorva-01 wants to merge 1 commit into
livekit:mainfrom
apoorva-01:fix/565-unpublish-deadlock

Conversation

@apoorva-01

@apoorva-01 apoorva-01 commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

unpublish_track only calls queue.task_done() at the bottom of the try, after the error raise.
So when the FFI reports an error the raise skips it, and that event stays on the room queue unconsumed. Room._listen_task does put_nowait(event) then await join(), so one stuck event hangs the whole room loop.

Moved task_done() to right after wait_for() returns, before the error check. The error still propagates and the queue always gets released.

Added a regression test that drives the same put/join loop. It hangs without the fix and passes with it.

on thing:publish_track right above has the same pattern. Left it out to keep this focused - happy to fix it here or in a follow-up.

closes #565

task_done() ran after the error raise, so a failed unpublish left the room queue's join() waiting forever and stalled the event loop.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

Open in Devin Review

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Track publishing errors stall the room event loop with the same deadlock fixed for unpublishing

The room queue event is not marked as done (queue.task_done() at livekit-rtc/livekit/rtc/participant.py:831) when a publish error is raised (livekit-rtc/livekit/rtc/participant.py:824), so the room event loop blocks forever waiting on the unconsumed event.

Impact: When publishing a track fails, the room stops processing all subsequent events, effectively freezing the connection.

Same deadlock pattern as the unpublish_track fix in this PR

This PR fixes the deadlock in unpublish_track by moving queue.task_done() before the error check. However, publish_track has the identical pattern:

  1. queue = self._room_queue.subscribe() at livekit-rtc/livekit/rtc/participant.py:816
  2. await queue.wait_for(...) at livekit-rtc/livekit/rtc/participant.py:819 — returns an event that the caller must mark done
  3. Error check at livekit-rtc/livekit/rtc/participant.py:823-824 raises PublishTrackError before task_done() at line 831
  4. The finally block at line 833-834 only calls unsubscribe, not task_done()

The room event loop at livekit-rtc/livekit/rtc/room.py:714-715 does:

self._room_queue.put_nowait(event)
await self._room_queue.join()

Since join() waits for all subscribers to call task_done(), the unconsumed event blocks the room event loop permanently.

The fix should mirror the unpublish_track fix: move queue.task_done() to immediately after wait_for returns, before the error check.

(Refers to lines 823-831)

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

1 participant