fix(runtime): make plugin and box connectors resilient

This commit is contained in:
Junyan Qin
2026-07-21 18:41:22 +08:00
parent 1765c43262
commit 998b76d53a
15 changed files with 699 additions and 236 deletions
+23
View File
@@ -3,6 +3,7 @@
from __future__ import annotations
import asyncio
import contextlib
import os
import sys
from typing import TYPE_CHECKING, Awaitable, Callable
@@ -27,6 +28,8 @@ class ManagedRuntimeConnector:
self.ap = ap
self.runtime_subprocess = None
self.runtime_subprocess_task = None
self._lifecycle_lock = asyncio.Lock()
self._closing = False
async def _start_runtime_subprocess(self, *args: str) -> None:
"""Launch a local runtime as a subprocess of the current Python interpreter.
@@ -86,3 +89,23 @@ class ManagedRuntimeConnector:
if self.runtime_subprocess_task is not None:
self.runtime_subprocess_task.cancel()
self.runtime_subprocess_task = None
async def _close_managed_subprocess(self) -> None:
"""Terminate, escalate, and reap the optional owned subprocess."""
process = self.runtime_subprocess
wait_task = self.runtime_subprocess_task
if process is not None and process.returncode is None:
with contextlib.suppress(ProcessLookupError):
process.terminate()
try:
await asyncio.wait_for(process.wait(), timeout=3)
except asyncio.TimeoutError:
with contextlib.suppress(ProcessLookupError):
process.kill()
await process.wait()
if wait_task is not None and wait_task is not asyncio.current_task():
if not wait_task.done():
wait_task.cancel()
await asyncio.gather(wait_task, return_exceptions=True)
self.runtime_subprocess = None
self.runtime_subprocess_task = None