From 909b40ba9641eec390507acb54b210ae85828139 Mon Sep 17 00:00:00 2001 From: Ivan Shvedunov Date: Thu, 26 Mar 2026 15:34:28 +0400 Subject: [PATCH] Fix export deadlock by replacing preexec_fn with nice command (#22641) subprocess.run() with preexec_fn forces Python to use fork() instead of posix_spawn(). In Frigate's main process (75+ threads), fork() creates a child that inherits locked mutexes from other threads. The child may deadlocks e.g. on a pysqlite3 mutex before it can exec() ffmpeg. Replace preexec_fn=lower_priority (which calls os.nice(19)) with prefixing the ffmpeg command with "nice -n 19", achieving the same priority reduction without requiring preexec_fn. This allows Python to use posix_spawn() which is safe in multithreaded processes. Fixes both the primary export path and the CPU fallback retry path. --- frigate/record/export.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/frigate/record/export.py b/frigate/record/export.py index 24bdb423f..1c02fd112 100644 --- a/frigate/record/export.py +++ b/frigate/record/export.py @@ -85,10 +85,6 @@ def validate_ffmpeg_args(args: str) -> tuple[bool, str]: return True, "" -def lower_priority() -> None: - os.nice(PROCESS_PRIORITY_LOW) - - class PlaybackSourceEnum(str, Enum): recordings = "recordings" preview = "preview" @@ -439,10 +435,9 @@ class RecordingExporter(threading.Thread): return p = sp.run( - ffmpeg_cmd, + ["nice", "-n", str(PROCESS_PRIORITY_LOW)] + ffmpeg_cmd, input="\n".join(playlist_lines), encoding="ascii", - preexec_fn=lower_priority, capture_output=True, ) @@ -467,10 +462,9 @@ class RecordingExporter(threading.Thread): ) p = sp.run( - ffmpeg_cmd, + ["nice", "-n", str(PROCESS_PRIORITY_LOW)] + ffmpeg_cmd, input="\n".join(playlist_lines), encoding="ascii", - preexec_fn=lower_priority, capture_output=True, )