perf: request-path hot-path optimizations — Tier 3–4 (#149) - #182
Conversation
There was a problem hiding this comment.
Code Review
This pull request optimizes account credential resolution by removing the per-account refresh lock, relying instead on the auth store's internal single-flighting. It also refactors quota assessment to pass QuotaState directly, optimizes boundary tracking in keepalive streams, and improves websocket idle timeout handling using a pinned sleep timer with a biased select. The reviewer suggested a medium-severity optimization in src/accounts.rs to avoid redundant quota evaluations and heap allocations for duplicate account aliases by querying only unique representatives.
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
Close the two coverage gaps surfaced while reviewing PR #182: - codex_ws run_turn: turn-level 300s idle timeout surfaces a transport error (paused-time test) — exercises the reused pinned Sleep + biased select. - keepalive BoundaryTracker::push: empty-chunk early return and the retained=3 copy_within offset (old-tail byte retention).
Greptile SummaryThis PR delivers Tier 3–4 hot-path optimizations to the request path: locking scope in
Confidence Score: 5/5All four hot-path changes are safe to merge: the quota-assessment refactor operates on a well-formed clone taken after expiry, the lock removal in resolve_or_cooldown is backed by auth-layer single-flighting and a direct regression test, the pinned idle timer preserves frame-over-deadline delivery via biased polling, and BoundaryTracker's bulk-copy path is verified correct for every sub-tail length (0, 1, 2, 3, ≥4) by the new unit tests. The quota assessment now runs on a cloned QuotaState after the entries mutex is released — expire_stale_quota still mutates under the lock, so the clone captures post-expiry state and the pure computation outside the lock is safe. The lock removal from resolve_or_cooldown is correct because CodexAuthStore::get_valid_chatgpt serializes refreshes internally per credential path; the new test validates that a held pool lock doesn't block valid-token resolution. The biased select! + pinned Sleep is a drop-in replacement for tokio::time::timeout with stronger frame-wins-at-deadline semantics. BoundaryTracker::push was verified manually and by tests for all retained lengths including the overlap case handled correctly by copy_within's memmove semantics. No files require special attention. Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant Caller
participant Pool as AccountPool
participant Lock as entries Mutex
participant Quota as assess_quota (pure)
Note over Caller,Quota: Before (all under lock)
Caller->>Lock: acquire
Lock->>Pool: expire_stale_quota
Lock->>Quota: assess_quota (holding lock)
Lock->>Quota: governing_weekly_reset (holding lock)
Lock-->>Caller: release
Note over Caller,Quota: After (quota assessment outside lock)
Caller->>Lock: acquire
Lock->>Pool: expire_stale_quota
Lock->>Pool: quota.clone()
Lock-->>Caller: release (lock dropped earlier)
Caller->>Quota: assess_quota(cloned_quota)
Caller->>Quota: governing_weekly_reset(cloned_quota)
Note over Caller,Quota: resolve_or_cooldown valid token path (Before)
Caller->>Pool: refresh_lock.lock().await
Pool->>Pool: resolve_chatgpt_account
Pool-->>Caller: Credential (lock released)
Note over Caller,Quota: resolve_or_cooldown valid token path (After)
Caller->>Pool: resolve_chatgpt_account (no pool lock)
Pool-->>Caller: Credential (concurrent safe)
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant Caller
participant Pool as AccountPool
participant Lock as entries Mutex
participant Quota as assess_quota (pure)
Note over Caller,Quota: Before (all under lock)
Caller->>Lock: acquire
Lock->>Pool: expire_stale_quota
Lock->>Quota: assess_quota (holding lock)
Lock->>Quota: governing_weekly_reset (holding lock)
Lock-->>Caller: release
Note over Caller,Quota: After (quota assessment outside lock)
Caller->>Lock: acquire
Lock->>Pool: expire_stale_quota
Lock->>Pool: quota.clone()
Lock-->>Caller: release (lock dropped earlier)
Caller->>Quota: assess_quota(cloned_quota)
Caller->>Quota: governing_weekly_reset(cloned_quota)
Note over Caller,Quota: resolve_or_cooldown valid token path (Before)
Caller->>Pool: refresh_lock.lock().await
Pool->>Pool: resolve_chatgpt_account
Pool-->>Caller: Credential (lock released)
Note over Caller,Quota: resolve_or_cooldown valid token path (After)
Caller->>Pool: resolve_chatgpt_account (no pool lock)
Pool-->>Caller: Credential (concurrent safe)
Reviews (4): Last reviewed commit: "test(perf): remove flaky idle-timer rese..." | Re-trigger Greptile |
greptile #182: the existing idle-timeout test only proved timeout-after- silence. Add a paused-time test that delivers a frame just before the deadline and confirms the reset gives a fresh full window (no premature timeout), then times out after renewed silence — pinning the reset-after- activity semantics and biased tie-breaking. Also resume real time during loopback handshake in both paused-time tests so a fully paused runtime cannot auto-advance to the idle timer before the first frame arrives.
turn_idle_timer_resets_after_each_frame raced the idle timer under CI load: a 1s margin before the original deadline was smaller than the real-time loopback handshake drift, so advancing could cross the initial sleep(IDLE_TIMEOUT) deadline before run_turn re-armed after frame 1. Widen the margin to 30s (>> handshake drift) and add a third frame whose receipt proves run_turn looped and re-armed past the original deadline before the test crosses it. Test-only; 20x consecutive local passes.
turn_idle_timer_resets_after_each_frame is not deterministic at this integration layer: proving reset-after-activity requires interleaving paused-clock fast-forward with real mid-stream socket I/O, and tokio's paused runtime auto-advances to the next timer whenever both the test and run_turn park waiting on that I/O — firing the idle timeout before the mid-stream frame is delivered. It passed locally (fast I/O) but raced under CI load. Keep the reliable timeout-after-silence test (turn_idle_timeout_surfaces_transport_error); defer reset-after-activity coverage to a follow-up that drives run_turn with a mock frame source instead of a real socket.
|



Summary
Tier 3–4 of the request-path hot-path performance audit (#149). Four sub-issues, one commit each:
AccountPool::select_order_innerno longer holds the globalentriesMutex across the O(N) quota assessment. The lock now covers only entry insertion, stale-quota expiry, and a minimal per-account state clone;assess_quota/governing_weekly_reset(pure computation) run after the lock is released. Multi-account failover ordering is unchanged.is_fable_modelis computed once per selection instead of ~2N times (removing per-account model lowercasing), threaded into the quota helpers as a precomputedbool. Provider-string construction is hoisted out of the per-account loop.resolve_or_cooldownno longer takes the per-account refresh lock for still-valid tokens.CodexAuthStore::get_valid_chatgptalready single-flights refreshes at the auth layer (perf: add single-flight to CodexAuthStore refresh to dedupe concurrent refreshes (auth/codex/auth.rs) #157 / perf(codex): single-flight CodexAuthStore refresh #168), so valid-token resolution now proceeds concurrently, while the expired-token refresh + atomic writeback stays serialized by the auth-layer path-keyed guard. The force-refresh (401 failover) path keeps its per-account lock (conservative scope).run_turnreuses one pinnedtokio::time::Sleepfor the idle timeout instead of registering a fresh timer per frame;BoundaryTracker::pushinspects at most the trailing 4 bytes of a chunk instead of rotating per byte.Notes
select!polls the frame source before the idle timer (biased) to preserve the inner-future-first semantics of thetokio::time::timeoutit replaces — a frame arriving as the deadline elapses is delivered, not dropped in favor of the timeout.Testing
cargo fmt --all --check— cleancargo clippy --all-targets --all-features -- -D warnings— cleancargo test --all-features --workspace— green (645 lib tests + all integration suites)\r\n\r\n(perf: reuse per-frame timeout timers and keepalive boundary rotation (codex_ws, keepalive) #160).Docs
Internal performance refactors only — no change to observable behavior, config keys, endpoints, CLI, or provider/model semantics, so no
README.md/docs//site/update is required (per AGENTS.md).Closes #156
Closes #158
Closes #159
Closes #160
Part of #149
Summary by cubic
Speeds up the request path by reducing pool lock scope and per-account work, allowing concurrent credential resolution for valid ChatGPT tokens, and trimming Codex WS idle-timer overhead. No behavior changes — just faster hot paths.
Refactors
entriesmutex only for insertion/expiry/snapshot; run quota assessment and weekly reset after unlock. Computeis_fable_modelonce per selection; provider string hoisted.QuotaStateisClone;assess_quota/governing_weekly_resettake a precomputedbool.resolve_or_cooldownskips the per-account refresh lock for valid tokens; expired-token refresh remains single-flighted inCodexAuthStore::get_valid_chatgpt. Tests ensure valid-token resolution doesn’t wait.run_turnreuses a pinnedtokio::time::Sleepand uses biasedselectso frames at the deadline are delivered.BoundaryTracker::pushbulk-copies only the trailing 4 bytes. Tests cover idle-timeout error surfacing and long-chunk/empty/3-byte boundary cases.Bug Fixes
Written for commit 3c8cb57. Summary will update on new commits.