perf(primer): drop pre-fire usage refresh so the Codex primer fires exactly on the slot
The Codex primer awaited refreshAllCodexAccountUsage + refreshActiveCodexUsage before firing, purely to feed the old usage-based warm-up gating. With forceAttempt the primer fires regardless of usage, so those pre-call refreshes only added variable latency (the few-hundred-ms jitter that pushed the call off the exact slot) and a needless dependency on the usage API. Fire first at the slot; refresh once afterwards for observability (never delaying the call). The hourly usage collector keeps cached usage current. Verified: typecheck, build, bundle-smoke; usage-primer + codex-warmup suites pass (primer now fires before any refresh; refreshAll no longer called). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -54,7 +54,7 @@ vi.mock('./codex-warmup.js', () => ({
|
||||
}));
|
||||
|
||||
describe('usage-primer', () => {
|
||||
it('refreshes Codex usage before primer selection and fires regardless of usage level', async () => {
|
||||
it('fires the Codex primer first with forceAttempt and refreshes usage only afterwards', async () => {
|
||||
callOrder.length = 0;
|
||||
refreshAllCodexAccountUsage.mockClear();
|
||||
refreshActiveCodexUsage.mockClear();
|
||||
@@ -63,7 +63,10 @@ describe('usage-primer', () => {
|
||||
const { runCodexPrimerCycle } = await import('./usage-primer.js');
|
||||
await runCodexPrimerCycle();
|
||||
|
||||
expect(callOrder).toEqual(['refreshAll', 'refreshActive', 'warmup']);
|
||||
// No pre-call usage refresh (that was the off-slot latency source); the
|
||||
// command fires immediately, then usage is refreshed for observability.
|
||||
expect(callOrder).toEqual(['warmup', 'refreshActive']);
|
||||
expect(refreshAllCodexAccountUsage).not.toHaveBeenCalled();
|
||||
expect(runCodexWarmupCycle).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
enabled: true,
|
||||
|
||||
@@ -3,10 +3,7 @@ import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
import { CODEX_WARMUP_CONFIG } from './config.js';
|
||||
import {
|
||||
refreshActiveCodexUsage,
|
||||
refreshAllCodexAccountUsage,
|
||||
} from './codex-usage-collector.js';
|
||||
import { refreshActiveCodexUsage } from './codex-usage-collector.js';
|
||||
import { runCodexWarmupCycle } from './codex-warmup.js';
|
||||
import { logger } from './logger.js';
|
||||
import { getAllTokens } from './token-rotation.js';
|
||||
@@ -153,8 +150,11 @@ async function runClaudePrimerCycle(): Promise<void> {
|
||||
|
||||
export async function runCodexPrimerCycle(): Promise<void> {
|
||||
try {
|
||||
await refreshAllCodexAccountUsage();
|
||||
await refreshActiveCodexUsage();
|
||||
// Fire immediately at the slot. There is NO pre-call usage refresh on
|
||||
// purpose: forceAttempt fires regardless of usage, so reading usage first
|
||||
// only added variable latency (the few-hundred-ms processing jitter that
|
||||
// pushed the call off the exact slot) and a needless dependency on the
|
||||
// usage API. The hourly usage collector keeps cached usage current.
|
||||
const result = await runCodexWarmupCycle(
|
||||
{
|
||||
...CODEX_WARMUP_CONFIG,
|
||||
@@ -164,17 +164,17 @@ export async function runCodexPrimerCycle(): Promise<void> {
|
||||
maxD7UsagePct: CODEX_PRIMER_MAX_D7_USAGE_PCT,
|
||||
},
|
||||
// forceAttempt: fire a real Codex command at *every* fixed slot,
|
||||
// bypassing the opportunistic warm-up skip gates. Without it, two slots
|
||||
// exactly 5h apart fall just under minIntervalMs (the primer fires a few
|
||||
// hundred ms after the slot) and the later slot is silently skipped.
|
||||
// bypassing the opportunistic warm-up skip gates (min-interval, stagger,
|
||||
// failure cooldown, usage/rate-limit filters).
|
||||
{ ignoreZeroUsageWindow: true, forceAttempt: true },
|
||||
);
|
||||
// Best-effort: a slot may land while the trailing 5h window is exhausted,
|
||||
// in which case this records `failed`. We deliberately do NOT try to
|
||||
// re-anchor to the reported reset time: the 5h limit is a trailing rolling
|
||||
// window whose reset slides forward with continued Codex usage, so no
|
||||
// single timed call can pin the reset to a fixed clock time.
|
||||
logger.info({ result }, 'Codex primer cycle finished');
|
||||
// Observability only — runs AFTER the call so it never delays it: refresh
|
||||
// so the newly-anchored reset window shows up in usage data/logs. A slot
|
||||
// may still land while the trailing 5h window is exhausted (records
|
||||
// `failed`); we do not chase the reported reset time, since a trailing
|
||||
// window keeps sliding with later usage.
|
||||
await refreshActiveCodexUsage();
|
||||
} catch (err) {
|
||||
logger.warn({ err }, 'Codex primer cycle threw');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user