fix(openviking): close session-boundary races on sync_turn and on_session_end

Two hardening fixes prompted by review on #28296:

1. sync_turn() now snapshots the target session id before spawning the
   worker. The previous code read self._session_id inside the worker, so
   a worker delayed past on_session_switch's bounded join could read the
   rotated-in NEW id and write the OLD turn's messages into the wrong
   session.

2. on_session_end() resets _turn_count to 0 after a successful commit,
   making the old-session commit path idempotent with the new switch
   hook. /new and compression call commit_memory_session() (which fires
   on_session_end) immediately before on_session_switch; without this,
   the old session would be committed twice. On commit failure we leave
   _turn_count > 0 so on_session_switch retries.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
(cherry picked from commit 2ea8d5c537)
This commit is contained in:
harshitAgr 2026-05-20 13:19:44 +03:00 committed by Hao Zhe
parent 813a4e3838
commit a30b40c73a
2 changed files with 120 additions and 1 deletions

View file

@ -589,6 +589,14 @@ class OpenVikingMemoryProvider(MemoryProvider):
if not user_content:
return
# Capture the target session id NOW, not inside the worker. Otherwise
# a delayed worker can read self._session_id after on_session_switch
# has rotated it (the switch's join on _sync_thread is bounded), and
# the OLD turn's content lands in the NEW session.
sid = str(session_id or self._session_id).strip()
if not sid:
return
self._turn_count += 1
def _sync():
@ -597,7 +605,6 @@ class OpenVikingMemoryProvider(MemoryProvider):
self._endpoint, self._api_key,
account=self._account, user=self._user, agent=self._agent,
)
sid = self._session_id
# Add user message
client.post(f"/api/v1/sessions/{sid}/messages", {
@ -642,6 +649,11 @@ class OpenVikingMemoryProvider(MemoryProvider):
try:
self._client.post(f"/api/v1/sessions/{self._session_id}/commit")
logger.info("OpenViking session %s committed (%d turns)", self._session_id, self._turn_count)
# Mark the session clean so a subsequent on_session_switch (fired
# by /new and compression right after commit_memory_session) skips
# its commit instead of double-committing. On commit failure we
# leave the count intact so the switch hook gets a retry.
self._turn_count = 0
except Exception as e:
logger.warning("OpenViking session commit failed: %s", e)