From a30b460b37a51cbf63c65c3dce92f7a006446f3e Mon Sep 17 00:00:00 2001 From: Chinesezjc Date: Sun, 2 Aug 2026 18:25:51 +0800 Subject: [PATCH] fix(code-runtime-python): keep the reply pump alive past a closed thread loop A binding called from a worker thread records that thread's loop for its reply. If the thread finished and closed its loop before the host reply arrived, _pump_replies' call_soon_threadsafe onto the closed loop raises RuntimeError; unguarded, that ends the pump task and strands every later reply. Wrap the schedule in a try/except that drops the moot reply (nothing awaits it) and keeps the pump serving. --- .../code-runtime/code-runtime-python/py/bootstrap.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/code-runtime/code-runtime-python/py/bootstrap.py b/packages/code-runtime/code-runtime-python/py/bootstrap.py index bd61b282e3..d215ff1370 100644 --- a/packages/code-runtime/code-runtime-python/py/bootstrap.py +++ b/packages/code-runtime/code-runtime-python/py/bootstrap.py @@ -877,7 +877,17 @@ async def _pump_replies( ok = bool(frame.get("ok")) value = frame.get("value") message = frame.get("message") - loop.call_soon_threadsafe(complete, fut, ok, value, message) + try: + loop.call_soon_threadsafe(complete, fut, ok, value, message) + except RuntimeError: + # The Future's loop has already closed — the thread that ran + # `asyncio.run(tools.x(...))` finished (its coroutine was cancelled + # or it exited) before this reply arrived, so nothing awaits the + # Future and the reply is moot. Drop it; scheduling onto a closed + # loop raises RuntimeError, and letting that escape would kill the + # pump and strand every later reply — the exact failure class this + # cross-loop delivery exists to prevent. + continue _SCALAR_RE = re.compile(