The code cited its plan instead of saying why: `E28 review J4`, `(R6 S3b)`, `S1 justified…`,
`deep-review round 5`. That plan lives in the private ops repo, so for every reader of this one the
citation was noise, and a sentence whose subject was the plan step ("round 2 showed…") hid its
lesson behind an id. Each one is gone and the "why" kept: a bare citation is deleted, a sentence
carrying a lesson is reworded around it ("a later attempt showed…").
Measured (`scripts/audit_metrics.py`, product code): 652 lines in 270 files carried an epic code by
the definition the next commit holds (507 / 241 by the old, two-digit-only one) -> 0. Across all
code, tests, scripts and configs: ~1100 epic-code lines plus ~320 sprint/round ids.
Behaviour unchanged, checked mechanically: every changed .py file has the same AST once docstrings
are blanked; css/sh/toml/yml/json files are identical once comments are stripped; the only
non-comment changes in TS/JS are test titles, one description string in a contract table, and five
ESLint messages, whose text is all the gates snapshot diff holds. Not touched: Markdown (docs and
the changelog keep their history), Alembic migrations, TV episode notation (`S2 · E5`), DESIGN.md
ids (`C1`, `B4`, `S3h`), tracker ids (`SEC-16`, `DX-17`).
One stale claim fixed on the way: test_hls_reaper's docstring said the player checkpoints "every
10 s whether or not it is playing", which plex/stream.py calls wrong; it now says what the code does.
104 lines
4.4 KiB
Python
104 lines
4.4 KiB
Python
"""Worker-child resource de-prioritization: the encoder thread cap, the `-threads` flag on the
|
|
browser-safe re-encode, and the child's startup renice/ionice/OMP handicap. These keep a CPU-heavy
|
|
transcode from pegging every core on the box it shares with the API, Postgres, and Plex playback."""
|
|
|
|
import subprocess
|
|
|
|
import pytest
|
|
|
|
from app.config import settings
|
|
from app.downloads import edit as editmod
|
|
from app.downloads import runner
|
|
|
|
|
|
class TestEncodeThreadCap:
|
|
def test_pinned_setting_wins(self, monkeypatch):
|
|
monkeypatch.setattr(settings, "download_ffmpeg_threads", 3)
|
|
assert editmod.encode_thread_cap() == 3
|
|
|
|
def test_zero_reserves_one_core(self, monkeypatch):
|
|
monkeypatch.setattr(settings, "download_ffmpeg_threads", 0)
|
|
monkeypatch.setattr(editmod.os, "cpu_count", lambda: 8)
|
|
assert editmod.encode_thread_cap() == 7
|
|
|
|
def test_single_core_box_never_caps_below_one(self, monkeypatch):
|
|
monkeypatch.setattr(settings, "download_ffmpeg_threads", 0)
|
|
monkeypatch.setattr(editmod.os, "cpu_count", lambda: 1)
|
|
assert editmod.encode_thread_cap() == 1
|
|
|
|
def test_unknown_cpu_count_falls_back(self, monkeypatch):
|
|
monkeypatch.setattr(settings, "download_ffmpeg_threads", 0)
|
|
monkeypatch.setattr(editmod.os, "cpu_count", lambda: None)
|
|
assert editmod.encode_thread_cap() == 1 # max(1, 2 - 1)
|
|
|
|
|
|
class TestBrowserSafeThreads:
|
|
def test_threads_flag_added_when_capped(self):
|
|
cmd = editmod.build_browser_safe_cmd(
|
|
"/in.mkv", "/out.mp4", reencode_video=True, reencode_audio=False, threads=2
|
|
)
|
|
assert "-threads" in cmd
|
|
assert cmd[cmd.index("-threads") + 1] == "2"
|
|
# The cap precedes the output file, so it binds the encoder (not input decoding).
|
|
assert cmd.index("-threads") < cmd.index("/out.mp4")
|
|
|
|
@pytest.mark.parametrize("threads", [0, None])
|
|
def test_no_threads_flag_when_uncapped(self, threads):
|
|
cmd = editmod.build_browser_safe_cmd(
|
|
"/in.mkv", "/out.mp4", reencode_video=True, reencode_audio=False, threads=threads
|
|
)
|
|
assert "-threads" not in cmd
|
|
|
|
|
|
class TestDeprioritize:
|
|
def test_renices_by_configured_increment(self, monkeypatch):
|
|
monkeypatch.setattr(settings, "download_child_nice", 12)
|
|
monkeypatch.setattr(settings, "download_child_ionice_class", 0) # skip ionice branch
|
|
calls = []
|
|
monkeypatch.setattr(runner.os, "nice", lambda n: calls.append(n))
|
|
monkeypatch.setattr(runner.os, "environ", {})
|
|
runner._deprioritize()
|
|
assert calls == [12]
|
|
|
|
def test_nice_zero_does_not_renice(self, monkeypatch):
|
|
monkeypatch.setattr(settings, "download_child_nice", 0)
|
|
monkeypatch.setattr(settings, "download_child_ionice_class", 0)
|
|
calls = []
|
|
monkeypatch.setattr(runner.os, "nice", lambda n: calls.append(n))
|
|
monkeypatch.setattr(runner.os, "environ", {})
|
|
runner._deprioritize()
|
|
assert calls == []
|
|
|
|
def test_sets_omp_budget_to_thread_cap(self, monkeypatch):
|
|
monkeypatch.setattr(settings, "download_child_nice", 0)
|
|
monkeypatch.setattr(settings, "download_child_ionice_class", 0)
|
|
monkeypatch.setattr(settings, "download_ffmpeg_threads", 4)
|
|
env: dict = {}
|
|
monkeypatch.setattr(runner.os, "environ", env)
|
|
runner._deprioritize()
|
|
assert env["OMP_NUM_THREADS"] == "4"
|
|
|
|
def test_ionice_invoked_when_binary_present(self, monkeypatch):
|
|
monkeypatch.setattr(settings, "download_child_nice", 0)
|
|
monkeypatch.setattr(settings, "download_child_ionice_class", 3)
|
|
monkeypatch.setattr(runner.os, "environ", {})
|
|
monkeypatch.setattr(runner.shutil, "which", lambda name: "/usr/bin/ionice")
|
|
ran = []
|
|
monkeypatch.setattr(
|
|
runner.subprocess,
|
|
"run",
|
|
lambda cmd, **kw: ran.append(cmd) or subprocess.CompletedProcess(cmd, 0),
|
|
)
|
|
runner._deprioritize()
|
|
assert ran and ran[0][:3] == ["ionice", "-c", "3"]
|
|
|
|
def test_ionice_skipped_when_binary_absent(self, monkeypatch):
|
|
monkeypatch.setattr(settings, "download_child_nice", 0)
|
|
monkeypatch.setattr(settings, "download_child_ionice_class", 3)
|
|
monkeypatch.setattr(runner.os, "environ", {})
|
|
monkeypatch.setattr(runner.shutil, "which", lambda name: None)
|
|
ran = []
|
|
monkeypatch.setattr(runner.subprocess, "run", lambda cmd, **kw: ran.append(cmd))
|
|
runner._deprioritize()
|
|
assert ran == []
|