@@ -864,13 +864,22 @@ async def _run_in_md2img_runtime(coro, timeout_seconds: Optional[int] = None):
|
||||
|
||||
future = runtime.submit(coro)
|
||||
awaitable_future = asyncio.wrap_future(future)
|
||||
if timeout_seconds is not None:
|
||||
return await asyncio.wait_for(awaitable_future, timeout=max(1, int(timeout_seconds)))
|
||||
# 关键修复:
|
||||
# 之前这里直接 return Future 对象,调用方 await 后只拿到 Future 本身,
|
||||
# 导致业务层误以为截图已完成,实际截图仍在后台执行,出现“先判失败后截图”的时序错乱。
|
||||
# 这里必须等待 Future 完成并返回真实结果,保证调用链严格串行。
|
||||
return await awaitable_future
|
||||
try:
|
||||
if timeout_seconds is not None:
|
||||
return await asyncio.wait_for(awaitable_future, timeout=max(1, int(timeout_seconds)))
|
||||
# 关键修复:
|
||||
# 之前这里直接 return Future 对象,调用方 await 后只拿到 Future 本身,
|
||||
# 导致业务层误以为截图已完成,实际截图仍在后台执行,出现“先判失败后截图”的时序错乱。
|
||||
# 这里必须等待 Future 完成并返回真实结果,保证调用链严格串行。
|
||||
return await awaitable_future
|
||||
except (asyncio.TimeoutError, asyncio.CancelledError):
|
||||
# 这里要把“当前调用方已放弃等待”的状态显式同步给 md2img 专用事件循环:
|
||||
# 1. 菜单、总结这类交互命令一旦在主链路超时,若不取消专用 loop 里的任务,
|
||||
# 浏览器截图仍可能继续跑完,白白占着浏览器与事件循环资源;
|
||||
# 2. 多次超时后,残留任务会在后台堆积,看起来像“插件流程整体卡住”;
|
||||
# 3. 因此这里在超时/取消时主动 future.cancel(),让下游尽快停止当前截图任务。
|
||||
future.cancel()
|
||||
raise
|
||||
|
||||
|
||||
def _get_browser_manager() -> _PersistentBrowser:
|
||||
|
||||
Reference in New Issue
Block a user