fix: harden realtime pipeline lifecycle

This commit is contained in:
Xin Wang
2026-09-07 08:27:52 +08:00
parent 43f2cc445e
commit 8025ed8aa0
12 changed files with 445 additions and 42 deletions
+60
View File
@@ -16,6 +16,8 @@ from services.object_storage import delete_object, put_object, storage_uri
MAX_WORKFLOW_TRACE_EVENTS = 1000
MAX_PENDING_HISTORY_MESSAGES = 256
HISTORY_FLUSH_TIMEOUT_SECONDS = 3.0
def _parse_timestamp(value: object) -> datetime:
@@ -39,6 +41,63 @@ class ConversationRecorder:
self._lock = asyncio.Lock()
self._seen_events: set[str] = set()
self._pending_artifacts: set[asyncio.Task[None]] = set()
self._pending_messages: asyncio.Queue[dict] = asyncio.Queue(
maxsize=MAX_PENDING_HISTORY_MESSAGES,
)
self._message_writer: asyncio.Task[None] | None = None
self._accepting_messages = True
def record_transport_message_later(self, message: object) -> None:
"""Keep database latency off the media path, with bounded buffering."""
if (
not self._accepting_messages
or not isinstance(message, dict)
or message.get("type") not in {
"transcript", "assistant-text-end", "workflow-event",
}
):
return
try:
self._pending_messages.put_nowait(deepcopy(message))
except asyncio.QueueFull:
logger.warning(f"对话历史写入积压,跳过本条记录: session={self.session_id}")
return
if self._message_writer is None:
self._message_writer = asyncio.create_task(
self._write_pending_messages(),
name=f"conversation-history-writer:{self.session_id}",
)
async def _write_pending_messages(self) -> None:
while True:
message = await self._pending_messages.get()
try:
await self.record_transport_message(message)
except Exception as exc:
logger.warning(f"对话历史写入失败: {type(exc).__name__}")
finally:
self._pending_messages.task_done()
async def flush_pending_messages(self) -> None:
"""Drain final transcripts before finishing the conversation row."""
self._accepting_messages = False
writer = self._message_writer
if writer is None:
return
try:
await asyncio.wait_for(
self._pending_messages.join(),
timeout=HISTORY_FLUSH_TIMEOUT_SECONDS,
)
except TimeoutError:
logger.warning(f"对话历史收尾超时,丢弃剩余缓冲: session={self.session_id}")
finally:
writer.cancel()
await asyncio.gather(writer, return_exceptions=True)
self._message_writer = None
while not self._pending_messages.empty():
self._pending_messages.get_nowait()
self._pending_messages.task_done()
@classmethod
async def start(
@@ -288,6 +347,7 @@ class ConversationRecorder:
raise
async def _finish(self, *, status: str) -> None:
await self.flush_pending_messages()
pending_artifacts = list(self._pending_artifacts)
if pending_artifacts:
await asyncio.gather(*pending_artifacts, return_exceptions=True)