feat(transcode): concurrency gate + relaxed cap — stop stampeding greg's media engine#52
Merged
Merged
Conversation
…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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
After v10.13.2 went live, 8-cell startup fired ~6 transcodes at once. Diagnosis from greg's Emby ffmpeg logs + hardware detection:
DG2 [Arc A310], i915) — NVENC/CUDA unavailable (Cannot load libcuda.so.1). Capable, but a cold-start burst of 6–8 overwhelms it.HTTP 500onlive.m3u8, partial/garbled HLS segments → clientd3d11 hwaccel initerrors + pixelation, and 3×-retry→skip = clips ending abruptly after ~10s.Fix — two levers, direct-play stays the reliable default
1. Transcode concurrency gate (
reliability.gate_auto_transcode+MAX_CONCURRENT_TRANSCODES, default 4, envHYPERWALL_MAX_CONCURRENT_TRANSCODES)._build_urldefers 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_TRANSCODESconstant; updated bitrate-cap expectations (33→50/25). Full suite green at v10.14.0.Out of scope / notes
ClitHero11(item 21515 —moov atom not found, fails direct and transcode) still needs deleting; owner scoped this PR to levers 1+2._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