13 KiB
status, date, definition
| status | date | definition |
|---|---|---|
| draft | 2026-05-20 | coarse |
Multi-CDN failover
Alternate-URI rotation for HLS sources with multiple CDN paths to the
same content. When a fetch fails on the active URI (after
network-resilience's retries are
exhausted), rotate to the next URI in the rendition's alternate-URI
list. Mux Video produces such sources via the ?redundant_streams=true
playback URL parameter; HLS spec / vendor conventions provide the
manifest-side declaration. Cluster G sister feature to
network-resilience; consumes the foundation's retry + circuit-
breaker primitives and adds the URI-rotation policy on top.
A Media-src feature for sources that genuinely require it (redundant-streams sources where the customer expects automatic failover) and a Player feature at Tier 2 (customer-customizable rotation policies). Notion epic #9 classifies as "Media-src? / Player?" — the ambiguity reflects the dual scope.
Status
- Composition: not implemented in
createSimpleHlsEngine. The parser doesn't recognize alternate-URI declarations; no rotation policy state; no failover behavior. Single-URI behavior throughout. - Definition depth: coarse — scope from Notion epic + Mux Video convention + network-resilience composition; SPF touchpoints sketched at the cluster level. Implementation details (parser syntax, state-slot shape, rotation defaults) tracked as open questions.
- Hard prerequisite: network-resilience. Rotation triggers on the foundation's retry-exhaustion signal; per-URI health tracking consumes the foundation's circuit-breaker state.
Phases of complexity
Tier 1 / Tier 2 framing per Notion epic #9 ("Tier 1: Parse spec-extension alternate URIs. Tier 2: Rotation policy, backoff strategy."). Each phase notes Naive vs Full depth where relevant per the Naive vs Full framing.
| Phase | Tier | What | Notes |
|---|---|---|---|
| Alternate-URI parsing + presentation surfacing | Tier 1 | Parser extracts alternate-URI lists from multivariant playlist (HLS spec extension or vendor convention; syntax open). Presentation Track data shape grows an alternateUris: string[] field (or similar) on each rendition |
Parser extension; presentation-modeling's Track shape grows. Tier 1 spec-compliant baseline: surface what the manifest says. Naive: parse the simplest known syntax (Mux convention). Full: support multiple alternate-URI declarations across HLS spec drafts + vendor variants |
| Active-URI state + initial selection | Tier 1 | New state slot — per-rendition active-URI tracking (e.g., selectedRenditionUris: Map<TrackId, string> or per-Track field on resolved presentation). Initial value: first URI in each rendition's alternateUris list. Behaviors consuming Track.uri (segment loading, playlist reload, manifest fetch) read the active URI rather than the canonical URI |
Constraint+filter shape: active-URI slot is the read-side for downstream consumers; rotation policy (Tier 2) is the write-side. Without rotation, this phase is degenerate-equivalent to single-URI behavior — Tier 1 alone provides parsing but not failover |
| Rotation on retry-exhaustion | Tier 2 | When network-resilience exhausts retries on the active URI for a given rendition, rotate to the next URI in the list. Active-URI slot updates; consumers re-fetch using the new URI. The rotation policy controls which URI is chosen next |
Consumes network-resilience's retry-exhaustion signal. Naive: round-robin through the list. Full: primary-preferred-with-fallback (return to primary when its circuit-breaker cools), or weighted, or region-aware. Live + multi-CDN composition: reload-loop failover during live consumes this phase too |
| Per-URI health tracking | Tier 2 | Combine network-resilience's per-URI circuit-breaker state into a health score per alternate URI. Rotation reads health when choosing next URI — skip known-unhealthy URIs without trying them. Health values surface from the breaker's healthy / cooldown / unhealthy state |
Consumes network-resilience's circuit-breaker primitive. Likely a derived signal (computed from breaker state). Naive: binary healthy/unhealthy from breaker state. Full: time-decayed health score that distinguishes "recently-cooled" from "long-healthy" |
| Customer-policy hooks | Tier 2 | Pluggable hooks: selectAlternateUri(failedUri, candidates, history) → string. Customer can override default rotation (region-preferred ordering, weighted, A/B testing, regulatory-compliant routing) |
Tier 2 customer-policy surface. Built-in defaults; hooks override when set. Adapter-layer customer-facing toggles ("prefer CDN A" UI) wire through these hooks |
What's in scope vs out of scope
In scope:
- All five phases above for HLS sources with alternate-URI declarations
- Parser support for alternate-URI lists (Mux convention syntax + any HLS spec extension forms)
- Active-URI state slot + rotation policy
- Integration with
network-resilience's retry-exhaustion + circuit- breaker primitives - Customer-pluggable rotation hooks
- Live + multi-CDN composition (reload-loop failover during live streams)
Out of scope (separate cluster G sister features):
- network-resilience (foundation, prerequisite) — retry + backoff + circuit-breaker. Multi-CDN consumes; doesn't reimplement.
- content-steering — HLS content- steering protocol. Server-side host-pool advertisement (dynamically updated). Different mechanism than static alternate-URI lists. Content-steering's pathway-priority composes with this feature's rotation primitive: pathway-priority is the dynamic ordering bias (a sort key); static manifest alternate-URI lists are the static candidate set.
Out of scope (different architectural layer):
- Adapter-layer customer-facing UI surfaces (e.g., "Switch CDN" buttons, region-preferred dropdowns). Consumer policy expressed via this feature's Tier 2 hooks.
- CDN-side load balancer / origin-shield / health-check infrastructure. Service-side concerns; engine reacts to what the CDN responds with.
- DRM key-server failover. Even when license fetches are CDN-routed, the failover concern lives under drm-support (license-fetch retries) + this feature's primitive may compose, but the key-server-specific rotation policy is DRM-side state.
Likely cross-cutting impact
Things this feature probably forces decisions on, not just additions:
- Per-rendition vs per-presentation active URI. Each rendition
can have its own alternate-URI list (different CDN paths per
bitrate variant) OR all renditions share the same active-URI
index. Per-rendition is more flexible (one rendition's CDN can be
unhealthy while others are fine); per-presentation is simpler
(one rotation state for the source). Lean: per-rendition. Affects
state-slot shape (
Map<TrackId, string>vs single index). - Active-URI slot writer composition. This feature writes the active URI; downstream behaviors read it. Single-writer slot — this feature's rotation behavior is sole writer. The slot is read by segment-loading, playlist-reload (when live-stream-support lands), manifest-fetch. Standard constraint+filter pattern.
- Parser surface for alternate-URI declarations. HLS spec
extensions vary; Mux uses one convention. Parser-pluggability
question from presentation-modeling
is sharpened by this feature — alternate-URI parsing extends the
parseMediaPlaylist/parseMultivariantPlaylistschema. Likely HLS-only initially; format-extension to DASH/MoQ adds different shapes. - Live + multi-CDN composition. During live playback, manifest reload-loop fetches periodically. Reload-fetch retry-exhaustion should trigger rotation (and the new URI's reload-loop continues). Cross-feature with live-stream-support (not implemented yet).
- Composition with
[content-steering]. Content-steering's server-advertised host pool changes the rotation's candidate set dynamically. Two composition shapes: (a) content-steering writes to thealternateUrislist (replacing the static manifest values); (b) content-steering writes a separatesteeredHostsslot that composes withalternateUris(intersect, prefer, etc.). Open question — when content-steering lands. - Rotation state across source changes. When the consumer changes
presentation.url, the active-URI state tears down with the source (per source-replacement's cascade). Per- URI circuit-breaker state innetwork-resiliencemay persist across sources for the same hosts (cross-source-resilience benefit). - Per-stream-type rotation coordination. A presentation with separate audio and video URIs (each possibly with their own alternate-URI lists) can rotate them independently. Live + multi- CDN with per-track rotation: each track's reload-loop manages its own active-URI rotation. Inherits live-stream-support's per-type reload-coordination open question.
Open questions
- Alternate-URI manifest syntax. HLS spec extension(s) vs Mux convention vs both. Parser scope question. Open until the first alternate-URI-bearing manifest lands as a test fixture.
- Per-rendition vs per-presentation active URI. Per the cross- cutting note; lean per-rendition for flexibility.
- Default rotation policy. Round-robin vs primary-preferred vs weighted. Lean: primary-preferred-with-circuit-breaker-cooldown- return.
- Composition with content-steering. Static
alternateUrismanifest values + dynamic content-steering host-pool: how to combine? Replacement vs intersection vs preference order? - Rotation-state preservation. Reset on source change (default)
vs preserve via the
bandwidthState-style cross-source-survival pattern (rare in this case — rotation state is per-URI, and URIs are per-source). - Customer-hook contract. Function signature, async semantics, failover-after-hook-failure policy. Same shape question as network-resilience's hook design; harmonize.
- DRM license-fetch interaction. When
drm-supportlands, license fetches go through CDN routing too. Multi-CDN rotation for license fetches: same feature, or DRM-side? - Per-stream-type rotation coordination. Independent rotation per type (video / audio / text) is the default; whether to allow coordinated rotation (single failover decision rotates all types) is an open Tier 2 question.
Related features
- network-resilience (hard prerequisite) — retry + backoff + circuit-breaker foundation. Multi-CDN consumes the retry-exhaustion signal (rotation trigger) and the per-URI circuit-breaker state (per-URI health tracking).
- content-steering — parallel sister; dynamic host-pool advertisement variant. Pathway-priority composes with this feature's rotation primitive (sort-key shape).
- presentation-modeling —
Trackdata shape growsalternateUrisfield; parser extension is in scope here. - live-stream-support (not yet implemented) — reload-loop failover during live consumes this feature's rotation primitive. Per-type reload coordination open question applies.
- source-replacement — active-URI state tears down via the resolved/unresolved cascade on source change.
- mse-mms-pipeline — segment-fetch
sites consume the active-URI slot indirectly via
Track.urireads. - drm-support (not implemented) — license- fetch failover question: same feature's rotation, or DRM-side?
- video-abr / audio-abr — ABR operates within a rendition; rotation operates on the rendition's URI. Orthogonal axes; both compose.
See also
- clusters.md § Selection resilience
— cluster G description; this feature is the selection-side
resilience sister to
network-resilience's response-error handling - clusters.md § Feature classification axes — Tier 1 / Tier 2 framing; Media-src? / Player? classification ambiguity
- presentation-modeling.md — parser- pluggability open question; alternate-URI parsing is one forcing function
- network-resilience.md — hard prerequisite; retry + circuit-breaker foundation
- SPF Epics Working Doc — source material; epic #9 (Multi-CDN Failover)
- Mux Video —
?redundant_streams=true— Mux Video convention for redundant-CDN sources