fix: harden realtime pipeline lifecycle
This commit is contained in:
@@ -12,13 +12,33 @@ from loguru import logger
|
||||
active_connections: set[object] = set()
|
||||
pipeline_tasks: set[asyncio.Task[None]] = set()
|
||||
connection_tasks: dict[object, asyncio.Task[None]] = {}
|
||||
connection_cleanup_tasks: set[asyncio.Task[None]] = set()
|
||||
DEFAULT_CLOSE_GRACE_SECONDS = 10.0
|
||||
|
||||
|
||||
async def _disconnect_connection(connection: object) -> None:
|
||||
"""Release media even when construction failed before transport startup."""
|
||||
try:
|
||||
async with asyncio.timeout(DEFAULT_CLOSE_GRACE_SECONDS):
|
||||
await connection.disconnect()
|
||||
except Exception as exc:
|
||||
logger.warning(f"Realtime 连接清理失败: {type(exc).__name__}")
|
||||
|
||||
|
||||
def _consume_pipeline_result(task: asyncio.Task[None], connection: object) -> None:
|
||||
pipeline_tasks.discard(task)
|
||||
if connection_tasks.get(connection) is task:
|
||||
connection_tasks.pop(connection, None)
|
||||
if connection in active_connections:
|
||||
active_connections.discard(connection)
|
||||
# Run after the pipeline task is done: closed handlers can safely wait
|
||||
# for that task without making pipeline shutdown wait on itself.
|
||||
cleanup = asyncio.create_task(
|
||||
_disconnect_connection(connection),
|
||||
name=f"realtime-disconnect:{getattr(connection, 'pc_id', id(connection))}",
|
||||
)
|
||||
connection_cleanup_tasks.add(cleanup)
|
||||
cleanup.add_done_callback(connection_cleanup_tasks.discard)
|
||||
try:
|
||||
error = task.exception()
|
||||
except asyncio.CancelledError:
|
||||
@@ -86,11 +106,15 @@ async def shutdown_active_sessions(
|
||||
) -> None:
|
||||
connections = list(active_connections)
|
||||
if connections:
|
||||
active_connections.difference_update(connections)
|
||||
await asyncio.gather(
|
||||
*(connection.disconnect() for connection in connections),
|
||||
*(_disconnect_connection(connection) for connection in connections),
|
||||
return_exceptions=True,
|
||||
)
|
||||
active_connections.difference_update(connections)
|
||||
|
||||
cleanup_tasks = list(connection_cleanup_tasks)
|
||||
if cleanup_tasks:
|
||||
await asyncio.gather(*cleanup_tasks, return_exceptions=True)
|
||||
|
||||
tasks = list(pipeline_tasks)
|
||||
if not tasks:
|
||||
@@ -106,4 +130,3 @@ async def shutdown_active_sessions(
|
||||
logger.info(
|
||||
f"Realtime 会话清理完成: normal={len(done)} cancelled={len(cancelled)}"
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user