fix(#4808): widen /api/sessions cache TTL while streaming to stop per-poll rebuilds
The frontend polls /api/sessions every 5s while a turn streams (static/sessions.js _streamingPollMs=5000), but the cache TTL was 2.5s (_SESSIONS_CACHE_TTL_SECONDS) — so every streaming poll landed in a fresh window and forced a full all_sessions() rebuild on the hot path under the global store LOCK, pinning CPU to 100% and starving token rendering on large stores (recurrence of #4672). The #4680 freeze-marker only de-dupes rebuilds WITHIN one TTL window; with polls spaced wider than the TTL it never helped. Fix: while _session_list_cache_streaming_freeze_marker() indicates an active stream, use _SESSIONS_CACHE_STREAMING_TTL_SECONDS=10.0 (> the 5s poll) so the sidebar holds steady across streaming polls. Live runtime state (active stream, sort order, pending flags) is overlaid on every response regardless of cache, and structural/settings changes still evict immediately via the source stamp — only a streaming session's own persisted title/message_count can lag up to 10s, which the #4672 design already deems acceptable. Idle path byte-for-byte unchanged. Diagnosis credit: investigation reproduced 6 streaming polls -> 6 rebuilds before, 1 after. Co-authored-by: batkuip <reporter>
This commit is contained in:
1 parent
27b6cd436e
commit
8eed95a25e
2 files changed
+88
-1
No files matched your search
+16
-1
@@ -1572,6 +1572,16 @@ def _clear_live_models_cache() -> None:
|
||||
# ── /api/sessions response cache (hot-sidebar response) ──────────────────────
|
||||
|
||||
_SESSIONS_CACHE_TTL_SECONDS = 2.5
|
||||
# #4808: while a turn is actively streaming the frontend polls /api/sessions on a
|
||||
# fixed cadence (static/sessions.js `_streamingPollMs` = 5000ms). With the idle TTL
|
||||
# of 2.5s, every streaming poll lands in a fresh window and forces a full
|
||||
# all_sessions() rebuild on the hot path under the global store LOCK — pinning CPU
|
||||
# and starving token rendering on large stores (recurrence of #4672). Hold the
|
||||
# sidebar cache steady for longer than one poll interval while streaming; live
|
||||
# runtime state (active stream, sort order, pending flags) is overlaid on every
|
||||
# response regardless of cache (_session_list_cache_overlay_runtime_rows), and
|
||||
# structural/settings changes still evict immediately via the source stamp.
|
||||
_SESSIONS_CACHE_STREAMING_TTL_SECONDS = 10.0
|
||||
_SESSIONS_CACHE_MAX_ENTRIES = 64
|
||||
_SESSIONS_CACHE_WAIT_SECONDS = 0.25
|
||||
_SESSIONS_CACHE_STALE_WAIT_SECONDS = 0.10
|
||||
@@ -1630,7 +1640,12 @@ def _session_list_cache_get(
|
||||
if stamp != current_stamp:
|
||||
_SESSIONS_CACHE.pop(key, None)
|
||||
return None, False
|
||||
fresh = (now - ts) < _SESSIONS_CACHE_TTL_SECONDS
|
||||
# #4808: widen the freshness window while a turn is streaming so the fixed
|
||||
# 5s streaming poll cadence doesn't force a full rebuild on every poll.
|
||||
ttl = _SESSIONS_CACHE_TTL_SECONDS
|
||||
if _session_list_cache_streaming_freeze_marker() is not None:
|
||||
ttl = _SESSIONS_CACHE_STREAMING_TTL_SECONDS
|
||||
fresh = (now - ts) < ttl
|
||||
if fresh:
|
||||
_SESSIONS_CACHE.move_to_end(key)
|
||||
return copy.deepcopy(payload), True
|
||||
|
||||
Reference in new issue
Block a user