snapshot websocket clients under the manager lock in the output loop

The output loop iterated ws4py's live websocket dict without its lock, so a client connecting or disconnecting mid-iteration raised "dictionary changed size during iteration" and killed the output loop. It now copies the clients under manager.lock once per frame and skips terminated ones, matching the jsmpeg and birdseye broadcasters.
This commit is contained in:
Josh Hawkins
2026-10-22 16:54:46 -05:00
parent 15c7f435ee
commit 4c47c6c85d
+10 -4
View File
@@ -285,11 +285,16 @@ class OutputProcess(FrigateProcess):
) )
preview_write_times[camera] = frame_time preview_write_times[camera] = frame_time
manager = websocket_server.manager
with manager.lock:
websockets = list(manager.websockets.values())
# send camera frame to ffmpeg process if websockets are connected # send camera frame to ffmpeg process if websockets are connected
if any( if any(
ws.environ["PATH_INFO"].endswith(camera) not ws.terminated
and ws.environ["PATH_INFO"].endswith(camera)
and ws_has_camera_access(ws, camera, self.config) and ws_has_camera_access(ws, camera, self.config)
for ws in websocket_server.manager for ws in websockets
): ):
# write to the converter for the camera if clients are listening to the specific camera # write to the converter for the camera if clients are listening to the specific camera
jsmpeg_cameras[camera].write_frame(frame.tobytes()) jsmpeg_cameras[camera].write_frame(frame.tobytes())
@@ -301,9 +306,10 @@ class OutputProcess(FrigateProcess):
and ( and (
self.config.birdseye.restream self.config.birdseye.restream
or any( or any(
ws.environ["PATH_INFO"].endswith("birdseye") not ws.terminated
and ws.environ["PATH_INFO"].endswith("birdseye")
and ws_has_camera_access(ws, "birdseye", self.config) and ws_has_camera_access(ws, "birdseye", self.config)
for ws in websocket_server.manager for ws in websockets
) )
) )
): ):