fix: usage API rate-limit guard and cleanup debug logging

This commit is contained in:
Eyejoker
2026-03-24 03:47:46 +09:00
parent 6a73421d4f
commit f6ba879e8a
4 changed files with 37 additions and 34 deletions

View File

@@ -58,13 +58,17 @@ function loadUsageDiskCache(): void {
if (fs.existsSync(USAGE_CACHE_FILE)) { if (fs.existsSync(USAGE_CACHE_FILE)) {
usageDiskCache = JSON.parse(fs.readFileSync(USAGE_CACHE_FILE, 'utf-8')); usageDiskCache = JSON.parse(fs.readFileSync(USAGE_CACHE_FILE, 'utf-8'));
} }
} catch { /* start fresh */ } } catch {
/* start fresh */
}
} }
function saveUsageDiskCache(): void { function saveUsageDiskCache(): void {
try { try {
fs.writeFileSync(USAGE_CACHE_FILE, JSON.stringify(usageDiskCache)); fs.writeFileSync(USAGE_CACHE_FILE, JSON.stringify(usageDiskCache));
} catch { /* best effort */ } } catch {
/* best effort */
}
} }
function cacheKey(token: string): string { function cacheKey(token: string): string {
@@ -104,7 +108,9 @@ async function fetchUsageForToken(
return null; return null;
} }
if (res.status === 429) { if (res.status === 429) {
logger.warn('Claude usage API: rate limited (429), returning cached data'); logger.warn(
'Claude usage API: rate limited (429), returning cached data',
);
return usageDiskCache[cacheKey(token)]?.usage ?? null; return usageDiskCache[cacheKey(token)]?.usage ?? null;
} }
if (!res.ok) { if (!res.ok) {

View File

@@ -48,15 +48,13 @@ interface FallbackConfig {
// ── State ──────────────────────────────────────────────────────── // ── State ────────────────────────────────────────────────────────
let cooldown: CooldownState | null = null; let cooldown: CooldownState | null = null;
let lastUsageAvailabilityCheck: let lastUsageAvailabilityCheck: {
| {
checkedAt: number; checkedAt: number;
result: 'available' | 'exhausted' | 'unknown'; result: 'available' | 'exhausted' | 'unknown';
} } | null = null;
| null = null; let usageAvailabilityCheckPromise: Promise<
let usageAvailabilityCheckPromise: 'available' | 'exhausted' | 'unknown'
| Promise<'available' | 'exhausted' | 'unknown'> > | null = null;
| null = null;
const USAGE_RECOVERY_RECHECK_MS = 30_000; const USAGE_RECOVERY_RECHECK_MS = 30_000;
@@ -213,7 +211,10 @@ export async function getActiveProvider(): Promise<string> {
} }
if (usageAvailability === 'exhausted') { if (usageAvailability === 'exhausted') {
// Current token exhausted — try rotating to another token (ignore cooldowns) // Current token exhausted — try rotating to another token (ignore cooldowns)
if (getTokenCount() > 1 && rotateToken(undefined, { ignoreRateLimits: true })) { if (
getTokenCount() > 1 &&
rotateToken(undefined, { ignoreRateLimits: true })
) {
logger.info( logger.info(
'Claude current token exhausted, rotated to next token — retrying', 'Claude current token exhausted, rotated to next token — retrying',
); );

View File

@@ -156,11 +156,7 @@ export function rotateToken(
for (let i = 1; i < tokens.length; i++) { for (let i = 1; i < tokens.length; i++) {
const idx = (currentIndex + i) % tokens.length; const idx = (currentIndex + i) % tokens.length;
const state = tokens[idx]; const state = tokens[idx];
if ( if (ignoreRL || !state.rateLimitedUntil || state.rateLimitedUntil <= now) {
ignoreRL ||
!state.rateLimitedUntil ||
state.rateLimitedUntil <= now
) {
state.rateLimitedUntil = null; state.rateLimitedUntil = null;
currentIndex = idx; currentIndex = idx;
logger.info( logger.info(