fix(quota): coalesce provider usage refreshes

This commit is contained in:
Bohdan Triapitsyn
2026-08-18 19:13:58 +03:00
parent 84e940a9e4
commit 3326ad0ea8
7 changed files with 267 additions and 39 deletions
@@ -67,6 +67,24 @@ describe('Claude quota provider', () => {
expect(result.usage.windows['5h'].usedPercent).toBe(5);
});
it('coalesces concurrent refreshes into one Anthropic request', async () => {
let resolveResponse;
const fetchMock = vi.fn().mockReturnValue(new Promise((resolve) => {
resolveResponse = resolve;
}));
vi.stubGlobal('fetch', fetchMock);
const first = fetchQuota();
const second = fetchQuota();
resolveResponse(jsonResponse(PAYLOAD));
const [firstResult, secondResult] = await Promise.all([first, second]);
expect(fetchMock).toHaveBeenCalledTimes(1);
expect(firstResult.ok).toBe(true);
expect(secondResult.ok).toBe(true);
});
it('keeps serving the last good values while Anthropic rate limits', async () => {
const fetchMock = vi.fn()
.mockResolvedValueOnce(jsonResponse(PAYLOAD))
@@ -158,6 +158,8 @@ const registry = {
}
};
const pendingFetches = new Map();
export const listConfiguredQuotaProviders = () => {
const configured = [];
@@ -174,7 +176,7 @@ export const listConfiguredQuotaProviders = () => {
return configured;
};
export const fetchQuotaForProvider = async (providerId) => {
const fetchQuotaForProviderUncoalesced = async (providerId) => {
const provider = registry[providerId];
if (!provider) {
@@ -200,6 +202,17 @@ export const fetchQuotaForProvider = async (providerId) => {
}
};
export const fetchQuotaForProvider = (providerId) => {
const existing = pendingFetches.get(providerId);
if (existing) return existing;
const pending = fetchQuotaForProviderUncoalesced(providerId).finally(() => {
if (pendingFetches.get(providerId) === pending) pendingFetches.delete(providerId);
});
pendingFetches.set(providerId, pending);
return pending;
};
export const fetchClaudeQuota = claude.fetchQuota;
export const fetchOpenaiQuota = openai.fetchQuota;
export const fetchGoogleQuota = google.fetchGoogleQuota;
@@ -1,7 +1,7 @@
import { describe, expect, it } from 'vitest';
import * as google from './google/index.js';
import { listConfiguredQuotaProviders } from './index.js';
import { fetchQuotaForProvider, listConfiguredQuotaProviders } from './index.js';
describe('quota provider registry', () => {
it('exposes google provider configuration helpers through the provider module', () => {
@@ -14,4 +14,13 @@ describe('quota provider registry', () => {
it('can list configured providers without missing provider exports', () => {
expect(() => listConfiguredQuotaProviders()).not.toThrow();
});
it('coalesces concurrent refreshes by provider ID', async () => {
const first = fetchQuotaForProvider('unsupported-test-provider');
const second = fetchQuotaForProvider('unsupported-test-provider');
expect(first).toBe(second);
await first;
expect(fetchQuotaForProvider('unsupported-test-provider')).not.toBe(first);
});
});