package youtube import ( "context" "time" "golang.org/x/time/rate" ) // globalFetchGate is the process-wide rate limiter for outbound timedtext/caption // fetches. A single instance is shared by ALL Adapter instances (the scheduler's // per-user runners + the web click-path) so they cannot collectively exceed the // per-egress-IP cap. ADR-014 item 2: the gate serialises/limits concurrent caption // fetches regardless of how many users or goroutines are upstream. The 429 is per // IP, not per user — so the gate is process-wide, not per-withUser, not per-video. // // Default 2s/req (burst 1): the first fetch passes immediately, subsequent fetches // are spaced at least 2s apart. Production overrides via SetFetchRate from config. var globalFetchGate = rate.NewLimiter(rate.Every(2*time.Second), 1) // SetFetchRate replaces the process-wide gate's rate with one token per interval. // Call once at startup from config (TAPIR_FETCH_RATE). A non-positive interval // installs an unlimited gate (rate.Inf) — used in dev/tests so nothing throttles. func SetFetchRate(interval time.Duration) { if interval <= 0 { globalFetchGate = rate.NewLimiter(rate.Inf, 1) return } globalFetchGate = rate.NewLimiter(rate.Every(interval), 1) } // WaitFetchGate blocks until the process-wide gate allows one timedtext fetch, // respecting ctx cancellation. Called from httpDo before every live outbound // caption fetch so the scheduler and the click-path share the same egress budget. func WaitFetchGate(ctx context.Context) error { return globalFetchGate.Wait(ctx) }