fix(quota): coalesce provider usage refreshes
This commit is contained in:
Binary file not shown.
@@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user