Skip to content

export ts --stitch --follow: a hard-killed importer can end the export on a missed decode deadline instead of a switch #6802

Closed

Description

@t0ms

Observation

Two importers publish one broadcast, the second started 8 s after the first, so the relay serves
the newer one. Two export ts --stitch --follow 10s --delay 2s subscribers read it. When the
serving importer is SIGKILLed, an export usually switches to the remaining importer as a marked
programme switch. In 3 of 13 runs, one of the two exports instead fails, and its follower gives up:

WARN moq_mux::container::consumer: current group evicted; skipping to next buffered group track="0.avc3" group=18 error=Moq(Stream(Unroutable))
WARN moq_mux::container::ts::follower: export failed, so not following path=t56.kill.8860 err=MPEG-TS output missed a decode deadline on PID 111 at 9945950 b/s, sent as far ahead as its decoder buffer holds; raise the multiplex rate
Error: MPEG-TS output missed a decode deadline on PID 111 at 9945950 b/s, sent as far ahead as its decoder buffer holds; raise the multiplex rate

The first importer is live throughout, and the other export of the same run switches to it. The
failure comes in the same millisecond as the killed importer's tracks going unroutable.

QUIC idle timeout (keep-alive a third) Runs An export failed
1 s 3 0
2 s 3 0
4 s 3 1
6 s 4 2

None failed on SIGTERM (6 runs), at any of the follower's 54 "broadcast replaced" switches (the
second importer's start, the killed one's restart), with the second importer on a separate encode
(3 hard kills), or when the serving importer's uplink was dropped for 1–2 s at a 1 s idle timeout
(6 runs, Linux).

Related: #5052 was the same error after a re-request onto a live route, fixed by #5109 (video held
through a silence drops as late). This is the follower's path after a hard kill.

Reproduction

main at 66af72315 (moq 0.14.2, moq-relay 0.17.2), macOS, loopback, one relay, moq-lite-06
negotiated. The source is a 1080i H.264 contribution file at 9.95 Mb/s CBR, played in real time
(tsp -P regulate --pcr-synchronous) into a file that each moq import ts follows from its own
start. --mux-rate is left at its default, the catalog's muxRate, so the output has the source's
rate and no headroom; whether a higher --mux-rate avoids the failure was not tested. Nothing in
the follower, export or scheduler has changed on main since.

Expected

The source going away mid-group is the same discontinuity the follower already handles when a
broadcast is replaced: a marked switch to the importer still announced, with the late access units
dropped, not a fatal scheduling error that also stops the follow.

(Written by Claude Opus 5.5)

Activity

  1. coderabbitai commented on Oct 25, 2026

    @coderabbitai
    Contributor
    🔗 Related PRs

    #6656 - feat(mux)!: TS export follows by cause, and --linger is --follow [merged]


    📝 Issue Planner

    Check the box below or use the @coderabbitai plan command to generate an implementation plan and prompts that you can use with your favorite coding assistant.

    • Create Plan

    🧪 Issue enrichment is currently in open beta.

    You can configure auto-planning by selecting labels in the issue_enrichment configuration.

    To disable automatic issue enrichment, add the following to your .coderabbit.yaml:

    issue_enrichment:
      auto_enrich:
        enabled: false

    💬 Have feedback or questions? Drop into our discord!

  2. added
    questBeing tracked/planned in a quest. See `quest/`
    on Oct 26, 2026
  3. kixelated commented on Oct 26, 2026

    @kixelated
    Collaborator

    Planned as quest/m1/ts-reliability/cut-arrival.md in #6844 (in the merge queue).

    Diagnosis (to be confirmed by a failing test first): a SIGKILLed importer is noticed only after the QUIC idle timeout. When its tracks then go Unroutable, the consumer's cut flushes the video frames still held for their DTS, stamped with the last frame's arrival from before the silence. They pass the jitter buffer as on time, land behind the schedule, and missed() ends the export. #5109 fixed the same stale stamp when a later frame settles the held frames; a cut settles them with no frame. This matches your table: idle timeouts at or under the 2 s delay never failed.

    Decisions

    • A cut carries the instant the loss was observed, and the frames it releases are judged as arriving then. Frames held through a silence longer than the delay drop as late, and the follower switches to the remaining instance.
    • Every flush path of held frames (cut, restart, skip, group end, end of track) is audited for the same stale arrival.
    • A genuine multiplex-rate miss stays fatal.
    • Covered by mock-time unit tests in export_timing_test.rs.
    • No backport: release has no follower or --stitch.

    The quest's PR will close this issue. To donate tokens, run /quest-start quest/m1/ts-reliability/cut-arrival.

    (Written by Claude Opus 5.5)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    questBeing tracked/planned in a quest. See `quest/`

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions