fix(agent): keep ORM results inside database worker

This commit is contained in:
InfinityPacer
2026-08-23 11:43:07 +08:00
parent f560c19d65
commit 9c4bead782
2 changed files with 20 additions and 14 deletions
+15 -13
View File
@@ -4,15 +4,12 @@ from __future__ import annotations
from dataclasses import dataclass from dataclasses import dataclass
from collections.abc import Callable from collections.abc import Callable
from typing import Any, Optional, Protocol, TypeVar from typing import Any, Optional, Protocol
from app.application.database import AsyncDatabaseExecutor from app.application.database import AsyncDatabaseExecutor
from app.schemas.agent import AgentChatSessionDetail, AgentChatSessionSummary from app.schemas.agent import AgentChatSessionDetail, AgentChatSessionSummary
T = TypeVar("T")
def has_custom_agent_chat_title(value: Optional[str]) -> bool: def has_custom_agent_chat_title(value: Optional[str]) -> bool:
"""判断会话标题是否已经脱离默认占位标题。""" """判断会话标题是否已经脱离默认占位标题。"""
return bool(value and value.strip() and value.strip() != "未命名会话") return bool(value and value.strip() and value.strip() != "未命名会话")
@@ -354,11 +351,16 @@ class AgentChatPersistenceService:
self._repository = repository self._repository = repository
self._async_executor = async_executor self._async_executor = async_executor
async def _run(self, operation: Callable[[SyncAgentChatRepository], T]) -> T: async def _run_write(
"""在线程 worker 中执行一个同步 AgentChat 持久化操作。""" self,
return await self._async_executor.run( operation: Callable[[SyncAgentChatRepository], object],
lambda: operation(self._repository()) ) -> None:
) """在线程 worker 内完成同步写入并丢弃仓储对象返回值。"""
def execute() -> None:
"""执行同步写入,不让 ORM 对象越过 worker 边界。"""
operation(self._repository())
await self._async_executor.run(execute)
async def async_append_display_messages( async def async_append_display_messages(
self, self,
@@ -373,7 +375,7 @@ class AgentChatPersistenceService:
client_session_id: Optional[str] = None, client_session_id: Optional[str] = None,
) -> None: ) -> None:
"""异步追加展示消息,等待同步事务取得确定终态。""" """异步追加展示消息,等待同步事务取得确定终态。"""
await self._run( await self._run_write(
lambda repository: repository.append_display_messages( lambda repository: repository.append_display_messages(
session_id=session_id, session_id=session_id,
user_id=user_id, user_id=user_id,
@@ -400,7 +402,7 @@ class AgentChatPersistenceService:
client_session_id: Optional[str] = None, client_session_id: Optional[str] = None,
) -> None: ) -> None:
"""异步保存展示消息快照,实际写入由有界 worker 承接。""" """异步保存展示消息快照,实际写入由有界 worker 承接。"""
await self._run( await self._run_write(
lambda repository: repository.save_display_messages( lambda repository: repository.save_display_messages(
session_id=session_id, session_id=session_id,
user_id=user_id, user_id=user_id,
@@ -422,7 +424,7 @@ class AgentChatPersistenceService:
messages: list[dict], messages: list[dict],
) -> None: ) -> None:
"""异步保存可恢复的原始消息。""" """异步保存可恢复的原始消息。"""
await self._run( await self._run_write(
lambda repository: repository.save_agent_messages( lambda repository: repository.save_agent_messages(
session_id=session_id, session_id=session_id,
user_id=user_id, user_id=user_id,
@@ -443,7 +445,7 @@ class AgentChatPersistenceService:
client_session_id: Optional[str] = None, client_session_id: Optional[str] = None,
) -> None: ) -> None:
"""异步写入首次生成的会话标题。""" """异步写入首次生成的会话标题。"""
await self._run( await self._run_write(
lambda repository: repository.update_title_if_empty( lambda repository: repository.update_title_if_empty(
session_id=session_id, session_id=session_id,
user_id=user_id, user_id=user_id,
+5 -1
View File
@@ -19,6 +19,7 @@ class _Executor:
def __init__(self) -> None: def __init__(self) -> None:
self.calls = 0 self.calls = 0
self.worker_thread_id: int | None = None self.worker_thread_id: int | None = None
self.results: list[object] = []
async def run(self, operation): async def run(self, operation):
"""在线程中执行一个完整的同步操作。""" """在线程中执行一个完整的同步操作。"""
@@ -26,7 +27,9 @@ class _Executor:
def invoke(): def invoke():
self.worker_thread_id = threading.get_ident() self.worker_thread_id = threading.get_ident()
return operation() result = operation()
self.results.append(result)
return result
return await asyncio.to_thread(invoke) return await asyncio.to_thread(invoke)
@@ -85,6 +88,7 @@ async def test_agent_chat_persistence_runs_sync_repository_inside_worker() -> No
) )
assert executor.calls == 4 assert executor.calls == 4
assert executor.results == [None, None, None, None]
assert executor.worker_thread_id != caller_thread_id assert executor.worker_thread_id != caller_thread_id
assert [name for name, _kwargs in repository.calls] == [ assert [name for name, _kwargs in repository.calls] == [
"append_display_messages", "append_display_messages",