mirror of
https://gitlab.com/vyla-entertainment/documentation.git
synced 2026-11-15 06:57:21 -05:00
83 lines
3.1 KiB
Markdown
83 lines
3.1 KiB
Markdown
# Error Handling & Resilience Guide
|
||
|
||
<p class="page-description">Strategies, error classification, and recovery patterns for handling network stalls, upstream rate limits, and streaming failures.</p>
|
||
|
||
## Overview
|
||
|
||
Upstream video providers can rotate domains, experience rate limits, or suffer transient outages. This guide explains how Vyla handles errors internally and how client players should respond.
|
||
|
||
---
|
||
|
||
## Error Classification
|
||
|
||
- **HTTP 400 Bad Request**: Missing or invalid TMDB ID or episode parameters. Validate input parameters on the client before requesting streams.
|
||
- **HTTP 429 Too Many Requests**: Upstream host rate limit triggered. The SDK applies backoff delays; clients should respect the `retry_after` header.
|
||
- **HTTP 502 Bad Gateway**: Upstream host unreachable or timed out. That provider is discarded while other scrapers continue running.
|
||
- **SSE Disconnect**: Network drop or backgrounded tab. If media is already buffering, do not interrupt. Otherwise, reconnect after a brief delay.
|
||
- **HLS Fatal Media Error**: Buffer stall or missing encryption key (`fatal: true`). Destroy the player instance and mount the next queued fallback stream.
|
||
|
||
---
|
||
|
||
## Client Fallback Strategy
|
||
|
||
Treat stream candidates as a prioritized queue rather than a single static link:
|
||
|
||
1. **Mount First Candidate**: Mount the first verified source that arrives over SSE.
|
||
2. **Queue Subsequent Sources**: Push subsequent incoming `source` events into a fallback array.
|
||
3. **Capture Timestamp on Error**: If a fatal error occurs, record `video.currentTime`.
|
||
4. **Teardown & Reconnect**: Call `hls.destroy()`, dequeue the next candidate, mount it, and seek back to the saved timestamp once metadata loads.
|
||
|
||
---
|
||
|
||
## Implementation Example
|
||
|
||
```javascript
|
||
function attachHlsPlayer(videoElement, candidate, fallbackQueue) {
|
||
const hls = new Hls({
|
||
maxBufferLength: 30,
|
||
maxMaxBufferLength: 60,
|
||
enableWorker: true
|
||
});
|
||
|
||
hls.loadSource(candidate.url);
|
||
hls.attachMedia(videoElement);
|
||
|
||
hls.on(Hls.Events.ERROR, (event, data) => {
|
||
if (!data.fatal) return;
|
||
|
||
switch (data.type) {
|
||
case Hls.ErrorTypes.NETWORK_ERROR:
|
||
hls.startLoad();
|
||
break;
|
||
case Hls.ErrorTypes.MEDIA_ERROR:
|
||
hls.recoverMediaError();
|
||
break;
|
||
default:
|
||
hls.destroy();
|
||
if (fallbackQueue.length > 0) {
|
||
const nextCandidate = fallbackQueue.shift();
|
||
const lastTime = videoElement.currentTime;
|
||
|
||
attachHlsPlayer(videoElement, nextCandidate, fallbackQueue);
|
||
videoElement.addEventListener('loadedmetadata', () => {
|
||
videoElement.currentTime = lastTime;
|
||
videoElement.play();
|
||
}, { once: true });
|
||
} else {
|
||
showErrorOverlay("All available streaming providers failed.");
|
||
}
|
||
break;
|
||
}
|
||
});
|
||
|
||
return hls;
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Timeout Budgets
|
||
|
||
- **First Candidate Timeout (8–10s)**: If no source event arrives within 8 seconds, inform the user that extended search is underway.
|
||
- **Hard Abort Timeout (20–25s)**: If no viable source is verified before the watchdog timer expires, close the connection and display an empty state with a retry button.
|