feat(api): retry Spotify 429s with backoff - #413
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
🟡 Changes recommended
The retry utility currently parses Retry-After but doesn’t use it to pace 429 retries, contradicting the stated behavior and risking immediate repeated rate-limit hits.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Adds a shared retry-with-backoff utility for Supabase edge functions and uses it to handle Spotify 429 rate limits, propagating Retry-After wait time through the API response so the Link Wizard UI can display a rate-limit-specific message.
Changes:
- Introduces
fetchWithRetry(+ unit tests) for retrying 429s with backoff and returning a structured rate-limit result. - Updates Spotify search and Spotify token acquisition to use the retry utility and surface rate-limit wait time.
- Plumbs
rateLimitRetryAfterthrough edge-function types, API Zod schema, and Link Wizard error formatting.
File summaries
| File | Description |
|---|---|
| supabase/functions/search-artist-links/types.ts | Adds optional rateLimitRetryAfter to provider outcomes/results. |
| supabase/functions/search-artist-links/spotify-adapter.ts | Switches Spotify search to fetchWithRetry and returns rate-limit info on 429. |
| supabase/functions/search-artist-links/index.ts | Includes rateLimitRetryAfter in the edge-function response when present. |
| supabase/functions/_shared/spotify-api/auth.ts | Uses fetchWithRetry for token requests and surfaces rate-limit failures. |
| supabase/functions/_shared/retry-utils.ts | Adds new retry/backoff helper and Retry-After parsing. |
| supabase/functions/_shared/retry-utils.test.ts | Adds Deno unit tests covering retry behavior and Retry-After parsing. |
| src/pages/admin/festivals/LinkWizard/useProviderCandidates.ts | Threads through rateLimitRetryAfter and formats a user-facing rate-limit message. |
| src/api/artistSearch/types.ts | Extends client schema/types to accept rateLimitRetryAfter. |
Review details
Suppressed comments (1)
supabase/functions/_shared/retry-utils.ts:50
- On 429, the retry sleep uses only exponential backoff; it should consider the parsed
Retry-Aftervalue so we don’t retry earlier than the server indicates (subject tomaxDelayMs).
if (attempt < maxRetries) {
const delay = Math.min(
initialDelayMs * Math.pow(2, attempt),
maxDelayMs,
);
- Files reviewed: 9/9 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
Deploy →
|
Playwright test resultsDetails
|
30b4ce7 to
8dc6671
Compare
Implement retry-with-backoff helper for handling Spotify API 429 responses: - New fetchWithRetry utility honors Retry-After header for rate limits - Spotify search and token refresh now retry twice with exponential backoff - Rate-limit errors are distinguishable from other failures with wait time - UI displays "Rate limited. Try again in Ns" message when applicable - Includes comprehensive unit tests for retry scenarios Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E2ci2Q1QgHtkMY93c2zf9C
Adds integration test covering repeated 429 responses surfacing rate-limit error through full request path. Tests three scenarios: - 429 exhausting retries: returns distinguishable rate-limit error with Retry-After seconds - 429 then success: recovers after one retry with backoff - Non-429 error: fails immediately without retry Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E2ci2Q1QgHtkMY93c2zf9C
…e UI from error wording Two fixes: 1. fetchWithRetry now incorporates Retry-After header into sleep duration using max(exponentialBackoff, retryAfterMs), capped at maxDelayMs, so we honor the server's requested wait time 2. buildErrorMessage detects rate-limit via rateLimitRetryAfter field directly instead of string matching on error text, decoupling UI from backend error wording Adds unit tests verifying: - Retry-After value is respected and delay is at least as long as requested - Large Retry-After values are capped at maxDelayMs to prevent hanging Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E2ci2Q1QgHtkMY93c2zf9C
…use fake timers in retry tests - getSpotifyAccessToken no longer reads .error off a RateLimitError result (TS2339) - searchSpotify breaks out of the artist loop on a 429 instead of hammering remaining candidates with requests that will just be rate-limited again - retry-utils.test.ts uses Deno's FakeTime instead of waiting on real delays, cutting ~3s of real time off the suite
8dc6671 to
89c9ad9
Compare
…integration tests getSpotifyAccessToken threw "Spotify credentials are not configured" in CI since SPOTIFY_CLIENT_ID/SECRET aren't set for deno test. Also the module-level token cache persisted across the file's three Deno.test cases (they share the same imported auth.ts instance), so tests after the first skipped the mocked token fetch and desynced their response queues.
Adds retry-with-backoff for Spotify API rate limits, honoring Retry-After header and surfacing rate-limit errors to the UI with wait time.
All tests passing; integration test for end-to-end rate-limit surface path planned in follow-up.
Verification
Generated by Claude Code