fix(session): cap messages at persistence boundary

Bind SessionManager saves to the existing raw archive path so SDK imports and other bypass saves cannot persist more than the file cap without archiving unconsolidated overflow.

Add an SDK regression test that exercises the real ingest path.

Refs #4787
This commit is contained in:
KDB
2026-07-21 13:47:18 +08:00
committed by Xubin Ren
parent fde55d06e2
commit 7cf3c71e3a
3 changed files with 37 additions and 1 deletions
+14 -1
View File
@@ -12,7 +12,7 @@ from copy import deepcopy
from dataclasses import dataclass, field
from datetime import datetime
from pathlib import Path
from typing import Any
from typing import Any, Callable
from weakref import WeakValueDictionary
from loguru import logger
@@ -427,6 +427,7 @@ class SessionManager:
# Preserve identity for sessions held by active callers without retaining idle ones.
self._overflow_cache: WeakValueDictionary[str, Session] = WeakValueDictionary()
self._max_cached_sessions = SESSION_CACHE_MAX_SIZE
self._file_cap_archiver: Callable[..., None] | None = None
def _remember(self, session: Session) -> None:
"""Keep recent sessions strongly cached without duplicating live objects."""
@@ -448,6 +449,10 @@ class SessionManager:
self._remember(session)
return session
def set_file_cap_archiver(self, archiver: Callable[..., None]) -> None:
"""Archive unconsolidated overflow whenever a session is persisted."""
self._file_cap_archiver = archiver
@staticmethod
def safe_key(key: str) -> str:
"""Public helper used by HTTP handlers to map an arbitrary key to a stable filename stem."""
@@ -669,6 +674,14 @@ class SessionManager:
write-back caching (e.g. rclone VFS, NFS, FUSE mounts) do not lose
the most recent writes.
"""
if self._file_cap_archiver is not None:
session.enforce_file_cap(
on_archive=lambda messages: self._file_cap_archiver(
messages,
session_key=session.key,
)
)
path = self._get_session_path(session.key)
tmp_path = path.with_suffix(".jsonl.tmp")