feat: proper 429 backoff + retry — prerequisite for auto-summarization default #1

Open
opened 2026-06-03 20:39:57 +00:00 by mathias · 0 comments
Owner

Problem

YouTube timedtext caption-fetch returns HTTP 429 (per-IP rate limit) under volume. Currently tapir silently maps 429 → SourceNone — identical to "genuinely no transcript". Users see skipped videos with no explanation and the video is never retried.

With multiple users this compounds: N users × M subscriptions × rapid scrapes = IP throttled immediately, making auto-summarization-as-default unsafe until this is solved.

Slices

T1 — Distinguish 429 from SourceNone in the adapter + store transcript status

  • FetchTranscript returns SourceNone on any non-200. Add domain.SourceRateLimited (or typed error) so the engine can distinguish "no captions" from "blocked, retry later".
  • Migration: videos.transcript_status (pending | rate_limited | fetched | none) so the runner can skip already-fetched and re-queue rate-limited across restarts.

T2 — Runner backoff: persist + respect rate-limit state across runs

  • On SourceRateLimited: record state in DB, skip on next run until a backoff window expires (TAPIR_FETCH_BACKOFF, e.g. 1h default).
  • Exponential + jitter backoff on repeated 429s for the same video.
  • TAPIR_FETCH_DELAY stays for per-video pacing; this adds per-video retry-after logic on top.

T3 — UI signal: show rate-limited state visibly

  • List shows rate-limited videos with a distinct "Retrying later" badge — not the Summarize button, not blank.
  • Once T1+T2 land and the throttle is honest: flip auto_summarize default from falsetrue (one-line migration change, gated on this issue).

Acceptance criteria

  • A 429 on captions is never silently treated as SourceNone.
  • Repeated runs correctly back off and eventually retry rate-limited videos.
  • Users see a visible "retrying later" state, not a silent skip.
  • After this lands: auto-summarization default can safely be flipped to true.
## Problem YouTube timedtext caption-fetch returns HTTP 429 (per-IP rate limit) under volume. Currently tapir silently maps 429 → SourceNone — identical to "genuinely no transcript". Users see skipped videos with no explanation and the video is never retried. With multiple users this compounds: N users × M subscriptions × rapid scrapes = IP throttled immediately, making auto-summarization-as-default unsafe until this is solved. ## Slices **T1 — Distinguish 429 from SourceNone in the adapter + store transcript status** - `FetchTranscript` returns `SourceNone` on any non-200. Add `domain.SourceRateLimited` (or typed error) so the engine can distinguish "no captions" from "blocked, retry later". - Migration: `videos.transcript_status` (`pending | rate_limited | fetched | none`) so the runner can skip already-fetched and re-queue rate-limited across restarts. **T2 — Runner backoff: persist + respect rate-limit state across runs** - On `SourceRateLimited`: record state in DB, skip on next run until a backoff window expires (`TAPIR_FETCH_BACKOFF`, e.g. 1h default). - Exponential + jitter backoff on repeated 429s for the same video. - `TAPIR_FETCH_DELAY` stays for per-video pacing; this adds per-video retry-after logic on top. **T3 — UI signal: show rate-limited state visibly** - List shows rate-limited videos with a distinct "Retrying later" badge — not the Summarize button, not blank. - Once T1+T2 land and the throttle is honest: flip `auto_summarize` default from `false` → `true` (one-line migration change, gated on this issue). ## Acceptance criteria - A 429 on captions is never silently treated as SourceNone. - Repeated runs correctly back off and eventually retry rate-limited videos. - Users see a visible "retrying later" state, not a silent skip. - After this lands: auto-summarization default can safely be flipped to true.
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mathias/tapir#1