Make camera streaming non-blocking to keep MQTT alive#101
Merged
Conversation
Stopping a camera stream ran on the paho MQTT network thread (via the load/unload module handlers) and joined the camera threads. When the configured RTSP IP is unreachable, those threads are stuck in OpenCV's ~30s grab timeout, so the join blocked the MQTT thread past the keepalive and the edge-sdk session dropped (robot briefly offline). Replace the spawn-per-start / join-per-stop CameraStreamer with a single long-lived daemon worker driven by two Events: - start()/stop()/shutdown() only toggle Events -> never block the caller, in particular the MQTT thread. - One worker serializes camera.open()/close(), removing the start/stop race that the old blocking join was guarding against. - The session body is wrapped so a failed open()/grab() can't kill the worker; it logs, backs off, and waits for the next start(). OpenCVCamera: capture thread is now a daemon and close() null-guards the join (the worker's `finally: close()` may run before a thread exists). RobotSession: register_camera shuts down a replaced streamer; disconnect signals shutdown on all streamers then bounded-joins (daemon threads guarantee process exit). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
leandropineda
approved these changes
Jun 2, 2026
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.
Your checklist for this pull request
🚨Please review the guidelines for contributing to this repository.
Description
When a camera's RTSP IP is unreachable, stopping the stream dropped the edge-sdk MQTT session and the robot went briefly offline.
load_module/unload_module camerasare dispatched synchronously on paho's single MQTT network thread, andCameraStreamer.stop()joined the camera threads — which are stuck in OpenCV's ~30s grab timeout on the bad IP — so the join blocked the MQTT thread past the keepalive.This replaces the spawn-per-start / join-per-stop
CameraStreamerwith a single long-lived daemon worker driven by twoEvents:start()/stop()/shutdown()only toggle Events, so they never block the caller — in particular the MQTT thread.camera.open()/close(), removing the start/stop race the old blocking join was guarding against.open()/grab()can't kill the worker; it logs, backs off, and waits for the nextstart().Supporting changes:
OpenCVCamera: capture thread is now a daemon, andclose()null-guards the join.RobotSession:register_camerashuts down a replaced streamer;disconnectsignals shutdown on all streamers then bounded-joins.Tests: updated
test_robot_session_register_camerafor the new lifecycle and added concurrency tests.toxpasses.Demo
Before — stopping the stream blocked the MQTT thread: the session disconnected, in-flight messages failed, and the robot reconnected only after OpenCV timed out:
After — the streaming/capture threads still tear down and OpenCV still errors on the unreachable stream, but the MQTT thread is never blocked: no disconnection, no failed sends, and
Robot data publishedkeeps flowing once per second: