From fcc984e79556cd2c9c529887f253838dc3264b5b Mon Sep 17 00:00:00 2001 From: joshkautz Date: Tue, 3 Mar 2026 17:30:13 -0600 Subject: [PATCH] Fix resource exhaustion from per-client GStreamer pipelines With set_shared(false) and SuspendMode::Reset (the current defaults), every RTSP client connection creates its own independent GStreamer pipeline and camera stream session. Each connection to the RTSP server (go2rtc, ffprobe, health check probes) opens a new Baichuan session with the camera. During long-running 24/7 operation, this causes: - File descriptor exhaustion from accumulated CLOSE_WAIT connections - Memory growth as pipeline resources are not fully reclaimed - Camera firmware hitting its concurrent session limit - RTSP server becoming unresponsive to new connections Switch to set_shared(true) so all RTSP clients share a single GStreamer pipeline, and SuspendMode::None to keep the pipeline alive when the last client disconnects. This eliminates the constant pipeline teardown/rebuild cycle and keeps resource usage stable. Addresses the file descriptor leaks reported in #370 and #380, and the memory growth reported in #366. --- src/rtsp/gst/factory.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/rtsp/gst/factory.rs b/src/rtsp/gst/factory.rs index c7a88c46..6d9c590a 100644 --- a/src/rtsp/gst/factory.rs +++ b/src/rtsp/gst/factory.rs @@ -35,11 +35,18 @@ impl Default for NeoMediaFactory { impl NeoMediaFactory { fn new() -> Self { let factory = Object::new::(); - factory.set_shared(false); + // Share a single GStreamer pipeline across all RTSP clients. + // Without this, each client (go2rtc, ffprobe, health checks) creates + // its own pipeline and camera stream session, exhausting resources + // and accumulating CLOSE_WAIT connections during 24/7 operation. + factory.set_shared(true); factory.set_eos_shutdown(false); factory.set_stop_on_disconnect(false); // factory.set_publish_clock_mode(gstreamer_rtsp_server::RTSPPublishClockMode::Clock); - factory.set_suspend_mode(gstreamer_rtsp_server::RTSPSuspendMode::Reset); + // Keep the pipeline alive when clients disconnect instead of tearing + // it down and rebuilding. Reset mode causes resource churn when + // monitoring tools periodically probe the stream. + factory.set_suspend_mode(gstreamer_rtsp_server::RTSPSuspendMode::None); factory.set_launch("videotestsrc pattern=\"snow\" ! video/x-raw,width=896,height=512,framerate=25/1 ! textoverlay name=\"inittextoverlay\" text=\"Stream not Ready\" valignment=top halignment=left font-desc=\"Sans, 32\" ! jpegenc ! rtpjpegpay name=pay0"); factory.set_transport_mode(RTSPTransportMode::PLAY); factory