fix(r5): address the fifth /code-review high round — 6 findings

- run_ffmpeg stops the process from ONE exit path (`except BaseException`), so
  an exception out of on_progress (a DB write) can no longer orphan a live
  ffmpeg after a 10s join on its pipes; _stop is now a no-op on a dead process
- both run_ffmpeg callbacks are throttled to ~1s (they were a DB round-trip per
  output line: ~10^5 queries on a long re-encode), mirroring the download hook
- volume arithmetic extracted to lib/playerVolume with unit tests; a corrupt
  level now falls back to the LAST GOOD one instead of full blast, and the
  sanitising happens where the stored value enters
- RSS is back to two except clauses (the shared tail already sits after the try)
- new tests: callback-exception cleanup, the two throttles; the fake Popen grew
  poll() and its wait count is now asserted

Mutation-checked: each new group goes red when its fix is reverted.
This commit is contained in:
2026-07-24 01:50:50 +02:00
parent fc82c8b47a
commit c4942eb590
8 changed files with 268 additions and 33 deletions
+20
View File
@@ -51,6 +51,11 @@ class _FakeProc:
self.killed = False
self.waits = 0
def poll(self):
# Popen.poll(): None while the process is alive. Our fake stays alive until it is stopped —
# `_stop` uses this to skip a process that has already gone.
return self._rc if self.terminated else None
def terminate(self):
self.terminated = True
# A terminated process's pipes hit EOF — that is how the reader threads finish.
@@ -132,6 +137,19 @@ def test_a_wedged_process_is_killed_by_the_stall_watchdog(fake_popen):
assert proc.terminated # the worker thread is freed, not parked forever
def test_a_callback_exception_still_stops_the_process(fake_popen):
# `on_progress` is a database write in production. A failure THERE used to unwind past a live
# ffmpeg — orphaning it, still encoding, after a 10s join on its pipes.
proc = fake_popen(_FakeProc(_FakeStream(["out_time_us=1000000\n"]), _FakeStream(block=True)))
def boom(_pct):
raise RuntimeError("database is down")
with pytest.raises(RuntimeError, match="database is down"):
edit.run_ffmpeg(["ffmpeg"], total_s=10, on_progress=boom, should_cancel=lambda: False)
assert proc.terminated
def test_a_process_that_ignores_sigterm_is_killed(fake_popen):
# `_stop`'s escalation: terminate, wait 5s, then SIGKILL. Without it a cancel could park the
# worker thread on a process that simply refuses to go.
@@ -150,6 +168,8 @@ def test_a_process_lingering_after_eof_is_stopped_and_reported(fake_popen):
with pytest.raises(RuntimeError, match="did not exit"):
edit.run_ffmpeg(["ffmpeg"], total_s=10, on_progress=lambda _p: None, should_cancel=lambda: False)
assert proc.terminated
# Two waits: the bounded grace wait that timed out, then _stop's own — never an unbounded one.
assert proc.waits == 2
def test_stderr_is_drained_while_the_process_runs(fake_popen):