diff --git a/src/enrich/discogs.service.ts b/src/enrich/discogs.service.ts index c406a33..8fc5763 100644 --- a/src/enrich/discogs.service.ts +++ b/src/enrich/discogs.service.ts @@ -38,7 +38,11 @@ export class DiscogsService { process.env.DISCOGS_TOKEN ?? '', process.env.DISCOGS_TOKEN2 ?? '', ].filter((t) => t.length > 0); - private readonly slots: number[] = this.tokens.map(() => 0); + // ВАЖНО: Discogs троттлит по IP (не по токену), поэтому с одного сервера + // общий лимит ~54/мин независимо от числа токенов. Токены ротируем вхолостую + // (выгода от 2-го токена — только на ВТОРОМ IP, напр. DE-воркер). + private nextSlot = 0; + private rr = 0; private readonly minIntervalMs = 1100; // Без токена обогащение жанрами не работает (поиск требует авторизации) @@ -46,18 +50,15 @@ export class DiscogsService { return this.tokens.length > 0; } - // Резервирует слот наименее загруженного токена, ждёт его и возвращает токен private async pickToken(): Promise { - let idx = 0; - for (let i = 1; i < this.slots.length; i++) { - if (this.slots[i] < this.slots[idx]) idx = i; - } const now = Date.now(); - const start = Math.max(now, this.slots[idx]); - this.slots[idx] = start + this.minIntervalMs; + const start = Math.max(now, this.nextSlot); + this.nextSlot = start + this.minIntervalMs; // глобальный интервал (IP-лимит) const wait = start - now; if (wait > 0) await new Promise((r) => setTimeout(r, wait)); - return this.tokens[idx]; + const token = this.tokens[this.rr % this.tokens.length]; + this.rr++; + return token; } async lookup(artist: string, song: string): Promise {