fix(exec): avoid flaky async subprocess timeouts
This commit is contained in:
@@ -3,6 +3,8 @@
|
||||
import asyncio
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
@@ -91,26 +93,31 @@ class ExecTool(Tool):
|
||||
env["PATH"] = env.get("PATH", "") + os.pathsep + self.path_append
|
||||
|
||||
try:
|
||||
process = await asyncio.create_subprocess_shell(
|
||||
with tempfile.TemporaryFile() as stdout_file, tempfile.TemporaryFile() as stderr_file:
|
||||
process = subprocess.Popen(
|
||||
command,
|
||||
stdout=asyncio.subprocess.PIPE,
|
||||
stderr=asyncio.subprocess.PIPE,
|
||||
stdout=stdout_file,
|
||||
stderr=stderr_file,
|
||||
cwd=cwd,
|
||||
env=env,
|
||||
shell=True,
|
||||
)
|
||||
|
||||
try:
|
||||
stdout, stderr = await asyncio.wait_for(
|
||||
process.communicate(),
|
||||
timeout=effective_timeout,
|
||||
)
|
||||
except asyncio.TimeoutError:
|
||||
deadline = asyncio.get_running_loop().time() + effective_timeout
|
||||
while process.poll() is None:
|
||||
if asyncio.get_running_loop().time() >= deadline:
|
||||
process.kill()
|
||||
try:
|
||||
await asyncio.wait_for(process.wait(), timeout=5.0)
|
||||
except asyncio.TimeoutError:
|
||||
process.wait(timeout=5.0)
|
||||
except subprocess.TimeoutExpired:
|
||||
pass
|
||||
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 = []
|
||||
|
||||
|
||||
Reference in New Issue
Block a user