give the shared sub stream grace on any capture thread reset

This commit is contained in:
Josh Hawkins
2026-08-24 07:22:50 -05:00
parent ccfe5cff46
commit a4e0e619df
2 changed files with 48 additions and 1 deletions
+43
View File
@@ -165,6 +165,49 @@ class TestCameraWatchdogStreamHealth(unittest.TestCase):
assert watchdog._stream_staleness(STREAM_TYPE_MAIN, now) is None
assert watchdog._stream_staleness(STREAM_TYPE_SUB, now) is not None
def test_detect_reset_grants_the_shared_sub_stream_grace(self):
watchdog = self._build_watchdog()
watchdog.detect_process_records_sub = True
watchdog.ffmpeg_detect_process = MagicMock()
watchdog.capture_thread = MagicMock()
watchdog.capture_thread.is_alive.return_value = False
watchdog.start_ffmpeg_detect = MagicMock()
now = datetime.now().astimezone(UTC)
stale = (now - timedelta(hours=1)).timestamp()
watchdog.latest_cache_segment_time[STREAM_TYPE_SUB] = stale
watchdog.latest_valid_segment_time[STREAM_TYPE_SUB] = stale
assert watchdog._stream_staleness(STREAM_TYPE_SUB, now) is not None
watchdog.reset_capture_thread(terminate=False)
# the sub check runs later in the same tick against a stale can_restart,
# so without this grace it would kill the just-restarted process again
assert (
watchdog._stream_staleness(STREAM_TYPE_SUB, datetime.now().astimezone(UTC))
is None
)
def test_detect_reset_leaves_sub_alone_when_not_shared(self):
watchdog = self._build_watchdog()
watchdog.detect_process_records_sub = False
watchdog.ffmpeg_detect_process = MagicMock()
watchdog.capture_thread = MagicMock()
watchdog.capture_thread.is_alive.return_value = False
watchdog.start_ffmpeg_detect = MagicMock()
now = datetime.now().astimezone(UTC)
stale = (now - timedelta(hours=1)).timestamp()
watchdog.latest_cache_segment_time[STREAM_TYPE_SUB] = stale
watchdog.latest_valid_segment_time[STREAM_TYPE_SUB] = stale
watchdog.reset_capture_thread(terminate=False)
assert (
watchdog._stream_staleness(STREAM_TYPE_SUB, datetime.now().astimezone(UTC))
is not None
)
def test_stale_threshold_follows_each_stream_segment_time(self):
watchdog = self._build_watchdog(
output_args={
+5 -1
View File
@@ -326,6 +326,11 @@ class CameraWatchdog(threading.Thread):
self.logger.info("Restarting ffmpeg...")
self.start_ffmpeg_detect()
# this process produces the sub stream's segments too, so it gets the
# same startup grace however the reset was triggered
if self.detect_process_records_sub:
self._grant_restart_grace([STREAM_TYPE_SUB], datetime.now().astimezone(UTC))
def run(self) -> None:
if self._update_enabled_state():
self.start_all_ffmpeg()
@@ -560,7 +565,6 @@ class CameraWatchdog(threading.Thread):
)
self._send_record_status(STREAM_TYPE_SUB, "offline", now)
self.reset_capture_thread()
self._grant_restart_grace([STREAM_TYPE_SUB], now_utc)
last_restart_time = now
# Prune expired reconnect timestamps