fix: fail fast on Spotify 429 instead of retrying into timeout

Retrying with wait times (23s + 60s + 60s) exceeded the 120s global
timeout and showed a generic timeout error. Now returns immediately
with a RATE_LIMITED error and shows the user how long to wait.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
HoneyandClaude Sonnet 4.6 committed 2026-05-11 00:05:41 +02:00
1 parent fbb00baa11
commit 859f4a458a
2 files changed
+25 -18

No files matched your search

+13 -18
View File
@@ -251,25 +251,16 @@ async function fetchSpotifyToken() {
async function _spApi(path, token) {
const url = path.startsWith('http') ? path : `https://api.spotify.com/v1${path}`;
for (let attempt = 0; attempt < 4; attempt++) {
const r = await _fetchTimeout(url, { headers: { Authorization: `Bearer ${token}` } });
if (r.status === 429) {
const retryAfter = parseInt(r.headers.get('Retry-After') || '5', 10);
// Long Retry-After = token is banned — invalidate cache and fail immediately
if (retryAfter > 60) {
_spTokenCache = null;
_spTokenExpiry = 0;
throw new Error(`Spotify-Token für ${Math.round(retryAfter / 3600)}h gesperrt (Rate Limit). Token-Cache geleert — nächster Versuch holt neuen Token.`);
}
const wait = (retryAfter + 1) * 1000;
console.log(`[spotify] 429 waiting ${retryAfter + 1}s`);
await new Promise(res => setTimeout(res, wait));
continue;
}
if (!r.ok) throw new Error(`Spotify API Fehler ${r.status}: ${path}`);
return r.json();
const r = await _fetchTimeout(url, { headers: { Authorization: `Bearer ${token}` } });
if (r.status === 429) {
const retryAfter = parseInt(r.headers.get('Retry-After') || '10', 10);
_spTokenCache = null;
_spTokenExpiry = 0;
console.log(`[spotify] 429 Retry-After=${retryAfter}s — failing fast`);
throw new Error(`RATE_LIMITED:${retryAfter}`);
}
throw new Error('Spotify API rate-limited — bitte kurz warten und erneut versuchen');
if (!r.ok) throw new Error(`Spotify API Fehler ${r.status}: ${path}`);
return r.json();
}
async function _spAllPlaylistTracks(id, token) {
@@ -423,6 +414,10 @@ app.post('/api/spotify/resolve', async (req, res) => {
if (e.message.includes('403') && e.message.includes('/playlists/')) {
return res.status(403).json({ error: 'EDITORIAL_PLAYLIST' });
}
if (e.message.startsWith('RATE_LIMITED:')) {
const secs = parseInt(e.message.split(':')[1], 10) || 30;
return res.status(429).json({ error: 'RATE_LIMITED', retryAfter: secs });
}
res.status(500).json({ error: e.message });
}
});