fix(explore): stop asking ListenBrainz after it refuses this client

Every popularity request answered 401 on 2026-10-05: 399 in one minute
of a real library's discography backfill, one rate-limited request per
artist to be told the same thing, each with its own log line.

A token is a property of the installation, not of the artist, so the
first 401 is the answer for the rest of that client's life. The refusal
is latched, logged once at warning level, and returned as
ErrListenBrainzUnauthorized — separate from the generic HTTP error
because it is the one failure no retry can fix. A 500 still does not
latch, so a transient failure leaves the artist unmarked and the next
run asks again.

The backfill also stops feeding artists once the client is refused: the
rest of the pass would be the same 401, and the artists stay unmarked
for a run that has a token.

Closes #284
This commit is contained in:
yonlu committed 2026-10-06 01:55:15 -04:00
1 parent c9b3048a20
commit bce8d27370
3 files changed
+157

No files matched your search

+18
View File
@@ -518,6 +518,13 @@ func (si *SearchIndex) BackfillLibraryDiscographies(ctx context.Context) {
break
}
// A refused client is refused for every artist: the rest of
// this pass would be the same 401, once per artist (#284). The
// artists stay unmarked, so a run with a token picks them up.
if indexLB.Unauthorized() {
break
}
work <- mbid
}
@@ -534,6 +541,17 @@ func (si *SearchIndex) BackfillLibraryDiscographies(ctx context.Context) {
return
}
if indexLB.Unauthorized() {
si.logger.Warn("discography backfill stopped early: "+
"listenbrainz refused this client, and a token is what it wants",
"artists", total, "of", len(mbids),
)
job.logf(jobs.LevelWarn, "Stopped early: ListenBrainz needs a token")
return
}
job.logf(jobs.LevelInfo, "Filled in "+strconv.Itoa(total)+" artists")
si.logger.Info("discography backfill complete", "artists", total)