fix(exec): avoid flaky async subprocess timeouts

This commit is contained in:
Hua
2026-03-15 19:13:22 +08:00
parent f1ed17051f
commit 0f5db9a7ff

View File

@@ -3,6 +3,8 @@
import asyncio import asyncio
import os import os
import re import re
import subprocess
import tempfile
from pathlib import Path from pathlib import Path
from typing import Any from typing import Any
@@ -91,26 +93,31 @@ class ExecTool(Tool):
env["PATH"] = env.get("PATH", "") + os.pathsep + self.path_append env["PATH"] = env.get("PATH", "") + os.pathsep + self.path_append
try: try:
process = await asyncio.create_subprocess_shell( with tempfile.TemporaryFile() as stdout_file, tempfile.TemporaryFile() as stderr_file:
process = subprocess.Popen(
command, command,
stdout=asyncio.subprocess.PIPE, stdout=stdout_file,
stderr=asyncio.subprocess.PIPE, stderr=stderr_file,
cwd=cwd, cwd=cwd,
env=env, env=env,
shell=True,
) )
try: deadline = asyncio.get_running_loop().time() + effective_timeout
stdout, stderr = await asyncio.wait_for( while process.poll() is None:
process.communicate(), if asyncio.get_running_loop().time() >= deadline:
timeout=effective_timeout,
)
except asyncio.TimeoutError:
process.kill() process.kill()
try: try:
await asyncio.wait_for(process.wait(), timeout=5.0) process.wait(timeout=5.0)
except asyncio.TimeoutError: except subprocess.TimeoutExpired:
pass pass
return f"Error: Command timed out after {effective_timeout} seconds" return f"Error: Command timed out after {effective_timeout} seconds"
await asyncio.sleep(0.05)
stdout_file.seek(0)
stderr_file.seek(0)
stdout = stdout_file.read()
stderr = stderr_file.read()
output_parts = [] output_parts = []