fix: ask clients to retry when live playlist is unavailable - #2963
Open
Ministorm3 wants to merge 2 commits into
Open
fix: ask clients to retry when live playlist is unavailable#2963Ministorm3 wants to merge 2 commits into
Ministorm3 wants to merge 2 commits into
Conversation
This branch is only reached when a session worker exists, so a failed trim is transient: either ffmpeg has not written the first playlist yet, or the read failed. Returning 404 told clients the stream was gone, and many abandon it rather than polling again. Return 503 with a Retry-After hint instead. Cancellation now logs at debug rather than warning, since the client has already disconnected and this endpoint is polled continuously by every viewer. Co-Authored-By: Claude Opus 5 <[email protected]>
Ministorm3
marked this pull request as draft
July 29, 2026 16:57
HlsPlaylistFilter.TrimPlaylist caught parse failures and returned an "empty" result: no segments, media sequence 0, empty playlist text. Callers treated that as success: the session endpoint served the empty playlist as 200, and TrimAndDelete wrote it over live.m3u8 on disk, turning a transient parse error into persistent corruption. Return Option<TrimPlaylistResult> with None on failure instead. The session endpoint now answers with the 503 retry response, and TrimAndDelete leaves the existing playlist untouched so the session can recover on the next cycle. Co-Authored-By: Claude Fable 5 <[email protected]>
Ministorm3
marked this pull request as ready for review
July 29, 2026 17:18
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
Two related failure paths around the live HLS playlist mishandle errors in ways that break players:
GET /iptv/session/{channelNumber}/hls.m3u8returns404wheneverTrimPlaylistyieldsNone. That happens whenlive.m3u8does not exist yet (ffmpeg has not written the first playlist), when the client disconnected, or when reading the playlist failed. This branch is only reachable whenTryGetWorkersucceeded, so the session demonstrably exists.404tells the client the resource is gone and carries no implication that it is temporary, so a client is behaving reasonably if it tears down a stream that was about to work.A playlist that fails to parse never even reached that branch:
HlsPlaylistFilter.TrimPlaylistcaught the exception and fabricated a "successful" result — an empty playlist with media sequence 0 and no segments. The session endpoint served that as a200, resetting the media sequence out from under the player. Worse, the segmenter'sTrimAndDeletewrote that empty playlist overlive.m3u8on disk, turning a transient parse error into persistent corruption.Change
Controller — Return
503 Service UnavailablewithRetry-After: 1, which is what RFC 9110 defines for a resource that is temporarily unavailable. One second is well under the 4s segment duration (OutputFormatHls.SegmentSeconds), so a retrying client picks the stream up on its next poll.Filter / session worker —
IHlsPlaylistFilter.TrimPlaylistandTrimPlaylistWithDiscontinuitynow returnOption<TrimPlaylistResult>and yieldNoneon failure, instead of fabricating an empty result (the bad playlist is still saved to the temp pool for diagnosis). Every failure now flows through one path: the session endpoint answersNonewith the503retry response above, andTrimAndDeleteleaves the on-disk playlist andPlaylistStartuntouched so the session can recover on the next cycle. This also removes an inconsistency where the filter rethrew only when saving the bad playlist also failed — a malformed playlist can no longer take down the session worker.Cancellation now logs at debug rather than warning — the client has already disconnected, and this endpoint is polled continuously by every viewer, so it was steady warning-level noise for a non-failure.
This only affects the Legacy streaming engine; the next engine's multi-variant playlist points at
live.m3u8and does not reach this action.Tests
ErsatzTV.Tests/Controllers/IptvControllerTests.cscovering all three branches ofGetLivePlaylist. Verified the retry test fails against the previousNotFound()and passes with the change.HlsPlaylistFilter_ShouldReturnNone_WhenPlaylistIsMalformed, a regression test for the fabricated-empty-result path; existing filter tests updated for theOptionreturn type. FullErsatzTV.Core.Testssuite passes (509).A collaboration between @Ministorm3 and Claude Code