From f0734348d032d5267e1816cf908f60fd742a97e5 Mon Sep 17 00:00:00 2001 From: Tam Nhu Tran Date: Mon, 8 Jun 2026 09:30:55 -0400 Subject: [PATCH] fix(usage): compute cost fallback lazily to stop event-loop stall normalizeCliproxyUsageHistoryDetail passed calculateHistoryDetailCost (a ~6ms model-pricing lookup) as an eager default argument to normalizePersistedNumber, so it ran for every record even when a persisted cost was already present. A few thousand records turned into a multi-second synchronous stall that wedged the bar summary aggregator and the dashboard startup prewarm. Compute the fallback only when cost is actually missing. --- .../usage/cliproxy-usage-transformer.ts | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/web-server/usage/cliproxy-usage-transformer.ts b/src/web-server/usage/cliproxy-usage-transformer.ts index 4e229a58..1036e58e 100644 --- a/src/web-server/usage/cliproxy-usage-transformer.ts +++ b/src/web-server/usage/cliproxy-usage-transformer.ts @@ -151,16 +151,20 @@ export function normalizeCliproxyUsageHistoryDetail( const outputTokens = normalizePersistedNumber(candidate.outputTokens); const cacheReadTokens = normalizePersistedNumber(candidate.cacheReadTokens); const requestCount = Math.max(1, normalizePersistedNumber(candidate.requestCount, 1)); - const cost = normalizePersistedNumber( - candidate.cost, - calculateHistoryDetailCost( - candidate.model, - provider, - inputTokens, - outputTokens, - cacheReadTokens - ) - ); + // Compute the cost fallback lazily. calculateHistoryDetailCost is ~6ms/call + // (model-pricing lookup); passing it as an eager default argument ran it for + // every record even when a persisted cost was already present, turning a few + // thousand records into a multi-second event-loop stall. + const cost = + typeof candidate.cost === 'number' && Number.isFinite(candidate.cost) + ? candidate.cost + : calculateHistoryDetailCost( + candidate.model, + provider, + inputTokens, + outputTokens, + cacheReadTokens + ); const accountId = typeof candidate.accountId === 'string' && candidate.accountId.length > 0