Skip to content

fix(video): escalate live reopen exhaustion for URL sources too - #343

Open
tschuegy wants to merge 1 commit into
superuser404notfound:mainfrom
tschuegy:fix/live-reopen-exhaustion-halt
Open

fix(video): escalate live reopen exhaustion for URL sources too#343
tschuegy wants to merge 1 commit into
superuser404notfound:mainfrom
tschuegy:fix/live-reopen-exhaustion-halt

Conversation

@tschuegy

@tschuegy tschuegy commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Problem

Both live reopen-exhaustion sites escalate only for the .customFactory transport that #199 introduced:

  • the barren-cycle cap in handlePumpFinished ("live source produced no segments across N reopen cycles; giving up"), and
  • the attempt cap at the end of performLiveReopen ("live reopen FAILED after N attempts; source considered permanently lost").

A URL-source live session that exhausts its reopen budget reaches the same terminal state with neither markLiveProductionHalted() nor onLiveSourceReset: the provider keeps advertising blocking reloads it can never satisfy (the -15410 shape the halt latch exists for), the playlist stays frozen, and the host is never asked to retune. That is exactly the zombie window #199 closed for engine-created ingest readers — still open on the most common transport.

Found while tracing a field freeze (same session as #340/#341/#342): the incident itself died through the live-muxerFailed hole #341 covers, but this adjacent exhaustion path has the identical failure shape for URL sources whose reopens run dry.

Fix

Extract the escalation decision as a pure function, liveReopenExhaustionEscalatesToHost(transport:), covering every reopenable transport, and use it at both sites. .none deliberately stays out: a transport-less source delegates to host retune before any reopen begins, and escalating it again would double-signal liveSourceReset.

Behavior for .customFactory is unchanged; .url now halts + signals on exhaustion instead of zombifying.

Tests

Pinned in Issue199RerouteRecoveryTests next to the existing transport-decision pins: .url and .customFactory escalate on exhaustion; .none never reaches the escalation.

🤖 Generated with Claude Code

Both reopen-exhaustion sites (the barren-cycle cap in
handlePumpFinished and the attempt cap at the end of performLiveReopen)
halted production and published onLiveSourceReset only for the
.customFactory transport superuser404notfound#199 introduced. A URL-source live session
that exhausted its reopen budget hit the same terminal state with
neither: the provider kept advertising blocking reloads it could never
satisfy, the playlist stayed frozen, and the host was never asked to
retune — the exact zombie window superuser404notfound#199 closed for engine-created ingest
readers, still open on the most common transport.

Extract the escalation decision as a pure function covering every
reopenable transport (.none stays out: it delegates to host retune
before any reopen begins, and escalating it again would double-signal
liveSourceReset) and use it at both sites.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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