Fix infinite Spotify rate limit loop from unguarded auth probes and swallowed errors

pull/253/head
Broque Thomas 2 months ago
parent 636af1f2f8
commit bc22bdca07

@ -441,18 +441,20 @@ class SpotifyClient:
error_str = str(e)
# Rate limit means we ARE authenticated — just throttled
if "rate" in error_str.lower() or "429" in error_str:
logger.warning("Spotify rate limited during auth check — treating as authenticated")
# Check if there's a Retry-After header indicating a long ban
# ANY rate limit on the auth probe means Spotify is actively throttling us.
# Always activate a global ban — even with a short or missing Retry-After.
# Without this, the probe→429→probe cycle repeats every ~60s forever.
retry_after = None
if hasattr(e, 'headers') and e.headers:
retry_after = e.headers.get('Retry-After') or e.headers.get('retry-after')
if retry_after:
try:
delay = int(retry_after)
if delay > _LONG_RATE_LIMIT_THRESHOLD:
_set_global_rate_limit(delay, 'is_spotify_authenticated')
except (ValueError, TypeError):
pass
try:
delay = int(retry_after) if retry_after else 0
except (ValueError, TypeError):
delay = 0
# Minimum 10 minutes for auth probe 429s — these indicate persistent throttling
ban_duration = max(delay, 600)
_set_global_rate_limit(ban_duration, 'is_spotify_authenticated')
logger.warning(f"Auth probe rate limited — activating {ban_duration}s global ban")
result = True
else:
logger.debug(f"Spotify authentication check failed: {e}")

@ -149,12 +149,14 @@ class SpotifyWorker:
time.sleep(min(cooldown, 60))
continue
# Auth guard — don't process anything without Spotify auth
if not self.client.is_spotify_authenticated():
# Try reloading config in case user re-authenticated via settings
# Auth guard — check if Spotify client is configured (no API call).
# We intentionally avoid calling is_spotify_authenticated() here
# because it makes an API probe that can re-trigger rate limits
# and lock users in an infinite rate-limit loop.
if not self.client.sp:
self.client.reload_config()
if not self.client.is_spotify_authenticated():
logger.debug("Spotify not authenticated, sleeping 30s...")
if not self.client.sp:
logger.debug("Spotify not configured, sleeping 30s...")
time.sleep(30)
continue
@ -343,6 +345,8 @@ class SpotifyWorker:
elif item_type == 'track_individual':
self._process_track_individual(item)
except SpotifyRateLimitError:
raise # Propagate to main loop so it activates the sleep/ban guard
except Exception as e:
logger.error(f"Error processing {item.get('type')} '{item.get('name', '')}': {e}")
self.stats['errors'] += 1

Loading…
Cancel
Save