Skip to content

feat(transcode): concurrency gate + relaxed cap — stop stampeding greg's media engine#52

Merged
tcconnally merged 1 commit into
mainfrom
feat/transcode-gate
Jul 15, 2026
Merged

feat(transcode): concurrency gate + relaxed cap — stop stampeding greg's media engine#52
tcconnally merged 1 commit into
mainfrom
feat/transcode-gate

Conversation

@tcconnally

Copy link
Copy Markdown
Owner

Problem

After v10.13.2 went live, 8-cell startup fired ~6 transcodes at once. Diagnosis from greg's Emby ffmpeg logs + hardware detection:

  • greg transcodes on an Intel Arc A310 (DG2 [Arc A310], i915) — NVENC/CUDA unavailable (Cannot load libcuda.so.1). Capable, but a cold-start burst of 6–8 overwhelms it.
  • Symptoms trace to that stampede: HTTP 500 on live.m3u8, partial/garbled HLS segments → client d3d11 hwaccel init errors + pixelation, and 3×-retry→skip = clips ending abruptly after ~10s.
  • These errors pre-date this PR (present in the "clean" soak and earlier) — the transcode arm has always been the flaky path here (the 2026-07-13 A/B bench that dropped the resolution gate). The feat(playback): burst-aware budgets — fix 8-cell cache-starvation freezes #49 bitrate cap just routed far more clips down it.

Fix — two levers, direct-play stays the reliable default

1. Transcode concurrency gate (reliability.gate_auto_transcode + MAX_CONCURRENT_TRANSCODES, default 4, env HYPERWALL_MAX_CONCURRENT_TRANSCODES). _build_url defers an AUTO escalation to direct-play when ≥ N cells already transcode; forced retries (a file that failed direct) bypass the gate. Cell transcode state is derived drift-free from the stream URL (.m3u8 = HLS transcode) at both commit points (cell.play + advance_to_prefetched) and read across siblings. Fail-safe: an overcount just yields more direct-play, and every cell re-derives its flag on its next play, so it can't saturate and permanently block.

2. Relaxed bitrate cap — burst headroom 3×→2× (33 → 50 Mbps at 8 cells), so only genuinely heavy 50–60+ Mbps outliers transcode; the bulk direct-plays.

New log tags to watch the gate work: [TRANSCODE/auto], [DIRECT/gated].

Tests

gate_auto_transcode (cap / passthrough / disable) + MAX_CONCURRENT_TRANSCODES constant; updated bitrate-cap expectations (33→50/25). Full suite green at v10.14.0.

Out of scope / notes

  • greg has no NVIDIA GPU today (owner: "maybe some day"). Wiring NVENC into the Emby container is the future big-capacity lever.
  • Corrupt file ClitHero11 (item 21515 — moov atom not found, fails direct and transcode) still needs deleting; owner scoped this PR to levers 1+2.
  • Pre-existing test noise _FakeCell has no attribute 'muted' in the soak suite is unrelated (this PR never touches .muted).

Verify

Deterministic gate logic is unit-tested. Live confirmation needs a rebuild (build.ps1, pwsh 7) + banner v10.14.0, then a run/soak: expect [DIRECT/gated] lines under load, ≤4 concurrent [TRANSCODE/auto], and the 500/hwaccel/pixelation storm gone.

🤖 Generated with Claude Code

…g's media engine

Post-v10.13.2, 8-cell startup fired ~6 transcodes at once. greg transcodes on
an Intel Arc A310 (NVENC/CUDA unavailable — libcuda.so.1 missing), which chokes
on that cold-start burst: HTTP 500 on live.m3u8, partial/garbled HLS segments →
client d3d11 hwaccel-init errors + pixelation, and 3x-retry→skip = clips ending
abruptly after ~10s. The transcode arm has always been the flaky path here (the
2026-07-13 A/B bench that dropped the resolution gate); the #49 bitrate cap just
routed far more clips down it.

Two levers, direct-play stays the reliable default:

1. Concurrency gate (reliability.gate_auto_transcode + MAX_CONCURRENT_TRANSCODES,
   default 4, env HYPERWALL_MAX_CONCURRENT_TRANSCODES). _build_url defers an AUTO
   escalation to direct-play when >= N cells already transcode; forced retries
   (a file that failed direct) bypass it. Cell transcode state is derived
   drift-free from the stream URL (.m3u8 = HLS transcode) at both commit points
   (cell.play + advance_to_prefetched) and read across siblings — fail-safe:
   overcount just means more direct-play, and every cell re-derives on its next
   play so it can't saturate.
2. Relaxed bitrate cap 3x->2x headroom (33->50 Mbps at 8 cells) so only genuinely
   heavy 50-60+ Mbps outliers transcode; the bulk direct-plays.

New log tags: [TRANSCODE/auto], [DIRECT/gated] (grep to watch the gate work).

Tests: gate (cap/passthrough/disable) + MAX_CONCURRENT_TRANSCODES constant;
updated bitrate-cap expectations 33->50/25. Suite green at v10.14.0.

Note: greg has no NVIDIA GPU today (owner: "maybe some day") — wiring NVENC into
the Emby container is the future big-capacity lever. Corrupt file ClitHero11
(item 21515, moov-atom-not-found, fails direct AND transcode) still needs
deleting — out of scope here (owner asked for levers 1+2 only).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@tcconnally
tcconnally merged commit e5b9bbd into main Jul 15, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant