Bản lưu ngày / Snapshot of 2026-10-02 · Xem bản mới nhất / See the latest version
WanduraDocsBeta
BetaDocs đang ở bản beta và còn thay đổi. Thấy chỗ sai, khó hiểu hoặc còn thiếu? Hãy cho chúng tôi biết.
Hướng dẫn

Phát mượt khi tải cao

Markdown
Trên trang này

TL;DR — Khi lưu lượng lên đỉnh, người xem chỉ nên thấy vòng xoay chờ một chút, không bao giờ thấy lỗi. Xin vé sớm (tập đang xem cộng một hai tập kế, trong một request), gửi viewer_ref ổn định để request lặp dùng lại vé, retry 429 và 503 bằng Retry-After, full jitter và ngân sách retry, và giữ tập hiện tại tiếp tục phát dù tập kế có chuyện gì.

Wandura làm gì khi bận

Khi Wandura
Bạn chạm rate limit playback Trả 429 kèm Retry-After, thường 1–2 giây: hạn mức được nạp lại mỗi giây.
Còn dưới khoảng 20 % hạn mức Từ chối vé prefetch trước ("reason": "prefetch_shed"); vé play vẫn được cấp bình thường.
Request play đến ngay khi vừa vượt hạn mức Giữ request tối đa khoảng 0,5 giây rồi mới trả 429.
Cùng người xem xin lại cùng tập, trên cùng thiết bị Trả lại vé đã cấp (còn ≥ 5 phút), không đếm lần nữa. Cần viewer_ref.
Không cấp kịp một vé 503 service_unavailable kèm Retry-After; trong một lô, chỉ phần tử đó lỗi.
Database của Wandura chậm Phục vụ catalog và kiểm giấy phép từ câu trả lời tốt gần nhất, cũ tối đa 5 phút.

Hai hệ quả cho code của bạn: luôn đọc Retry-After thay vì tự giả định một con số, và cho request xin vé timeout phía client ít nhất 5 giây.

Xin vé sớm

  1. Xin theo lô các tập kế. Khi người xem bắt đầu tập N, gửi một request: N với "intent": "play", cộng N+1 và N+2 dưới dạng prefetch nếu người xem được phép xem chúng. Một lượt gọi, tối đa ba vé.
  2. Dùng lại vé cho đúng. Vé gắn với một thiết bị. Chỉ dùng lại cho cùng người xem, cùng thiết bị, cùng tập và cùng intent, và chỉ tới 5 phút trước expires_at. Wandura làm việc này cho bạn khi bạn gửi viewer_ref ổn định; cache ở backend theo cùng khoá cũng được. Không bao giờ dùng chung vé giữa các thiết bị.
  3. Gửi viewer_ref ổn định: HMAC của user ID cộng hash của install ID. Không bao giờ theo phiên, không bao giờ chứa dữ liệu cá nhân.
{
  "episodes": [
    { "film_ref": "the-heiress-returns", "episode_no": 4, "intent": "play" },
    { "film_ref": "the-heiress-returns", "episode_no": 5, "intent": "prefetch" },
    { "film_ref": "the-heiress-returns", "episode_no": 6, "intent": "prefetch" }
  ],
  "union_info": "<device ID from the Player SDK>",
  "drm_kek": "<device public key from the Player SDK>",
  "viewer_ref": "k3Jd9sQm2vXa7LpT0bWc1e:Zr8uYq2nM4a"
}

Mỗi phần tử trong response có status riêng: một phần tử có thể 200 trong khi phần tử khác 404 not_ready (quá tập cuối), 429 (một prefetch bị tạm dừng) hoặc 503 kèm retry_after. Chỉ retry những phần tử hỏng mà bạn cần.

Retry 429 và 503 cho đúng

Các luật (status nào, Retry-After, full jitter, mức trần, timeout, ngân sách, số request song song) nằm ở chính sách retry chuẩn. Trong code:

/** How hard to try. INTERACTIVE = a viewer is waiting; BACKGROUND = a sync job. */
export type RetryPolicy = {
  maxRetries: number; // retries after the first attempt
  baseMs: number; // first backoff step
  capMs: number; // largest backoff step
  timeoutMs: number; // per attempt
  deadlineMs: number; // the whole call, retries included
};
export const INTERACTIVE: RetryPolicy = { maxRetries: 3, baseMs: 500, capMs: 8_000, timeoutMs: 8_000, deadlineMs: 15_000 };
export const BACKGROUND: RetryPolicy = { maxRetries: 5, baseMs: 1_000, capMs: 30_000, timeoutMs: 15_000, deadlineMs: 120_000 };

/** Retry only what can succeed later: network errors, 429, 500, 502 and 503 (except 503 `not_ready`). */
export function isRetryable(status: number | null, errorCode?: string): boolean {
  if (status === null) return true;
  if (status === 503) return errorCode !== 'not_ready';
  return status === 429 || status === 500 || status === 502;
}

/** Wait before retry number `attempt` (0-based): Retry-After (+ up to 1 s jitter) wins, else full jitter under the cap. */
export function backoffMs(attempt: number, retryAfterS: number | null, p: RetryPolicy, random = Math.random): number {
  if (retryAfterS !== null && retryAfterS > 0) return retryAfterS * 1_000 + random() * 1_000;
  return random() * Math.min(p.capMs, p.baseMs * 2 ** attempt);
}

/** Retries may be at most 10 % of the requests of the last minute (never fewer than 10 a minute). */
export class RetryBudget {
  private sent = 0;
  private retries = 0;
  private since = Date.now();
  private roll() {
    if (Date.now() - this.since > 60_000) { this.sent = 0; this.retries = 0; this.since = Date.now(); }
  }
  noteRequest() { this.roll(); this.sent++; }
  tryRetry(): boolean {
    this.roll();
    if (this.retries >= Math.max(10, this.sent * 0.1)) return false;
    this.retries++;
    return true;
  }
}

Endpoint backend dùng nó, với request theo lô và cách xử lý từng phần tử: Luồng playback và paywall.

Giữ người xem tiếp tục xem

  • Vòng xoay chờ, không phải lỗi. Trong lúc backend đang retry, giữ trạng thái đang tải. Chỉ hiện Retry khi đã hết ngân sách (khoảng 15 giây).
  • Tập hiện tại tiếp tục phát. Request cho tập kế bị hỏng không bao giờ làm dừng hay tải lại tập đang trên màn hình.
  • Prefetch bị từ chối không phải lỗi. Không làm gì người xem thấy được; xin với "intent": "play" khi người xem tới tập đó.
  • Không bao giờ hiện mã status thô.

Code phía app, bằng Swift và Kotlin, làm đúng như vậy: iOS, Android.

Đọc response một cách dễ tính

Bỏ qua trường lạ, coi giá trị lạ là trường hợp mặc định, và xử mã lỗi lạ theo nhóm status. Xem Versioning và API tiến hoá.

Danh sách kiểm tra

  • Bắt đầu một tập gửi một request: play cho tập đó, prefetch cho các tập kế đã mở khoá.
  • Vé chỉ được dùng lại theo người xem, thiết bị, tập và intent, không bao giờ dùng chéo thiết bị, tới 5 phút trước expires_at.
  • viewer_ref ổn định theo người xem và thiết bị, và không chứa dữ liệu cá nhân.
  • 429 và 503 được retry sau Retry-After cộng jitter; nếu không có thì exponential backoff với full jitter.
  • Tối đa 3 lần retry cho mỗi request tương tác, và ngân sách retry 10 % mỗi phút.
  • Request xin vé có timeout phía client ít nhất 5 giây.
  • Prefetch bị từ chối không có tác động nhìn thấy được, và không bao giờ làm dừng tập hiện tại.

Cập nhật 02/10/2026 · Lịch sử thay đổi (3)

↑↓ chọnEnter mởEsc đóng

Gửi góp ý

Góp ý được gửi thẳng tới đội Wandura, kèm địa chỉ trang này.

0 / 4000