feat: centralize command execution timeout constant for sandbox providers

This commit is contained in:
Harry 2026-02-14 16:01:12 +08:00
parent 5cfb3d70e1
commit dd8385abf1
3 changed files with 25 additions and 13 deletions

View File

@ -0,0 +1,10 @@
"""
Constants for virtual environment providers.
Centralizes timeout and other configuration values used across different sandbox providers
(E2B, SSH, Docker) to ensure consistency and ease of maintenance.
"""
# Command execution timeout in seconds (5 hours)
# Used by providers to limit how long a single command can run
COMMAND_EXECUTION_TIMEOUT_SECONDS = 5 * 60 * 60 # 18000 seconds

View File

@ -30,6 +30,7 @@ from core.virtual_environment.channel.transport import (
TransportReadCloser,
TransportWriteCloser,
)
from core.virtual_environment.constants import COMMAND_EXECUTION_TIMEOUT_SECONDS
logger = logging.getLogger(__name__)
@ -292,6 +293,7 @@ class E2BEnvironment(VirtualEnvironment):
cwd=cwd,
on_stdout=lambda data: stdout_stream_write_handler.write(data.encode()),
on_stderr=lambda data: stderr_stream_write_handler.write(data.encode()),
timeout=COMMAND_EXECUTION_TIMEOUT_SECONDS,
)
except Exception as e:
# Capture exceptions and write to stderr stream so they can be retrieved via CommandFuture

View File

@ -27,6 +27,7 @@ from core.virtual_environment.__base.virtual_environment import VirtualEnvironme
from core.virtual_environment.channel.exec import TransportEOFError
from core.virtual_environment.channel.queue_transport import QueueTransportReadCloser
from core.virtual_environment.channel.transport import TransportWriteCloser
from core.virtual_environment.constants import COMMAND_EXECUTION_TIMEOUT_SECONDS
logger = logging.getLogger(__name__)
@ -55,9 +56,8 @@ class SSHSandboxEnvironment(VirtualEnvironment):
_DEFAULT_SSH_HOST = "agentbox"
_DEFAULT_SSH_PORT = 22
_DEFAULT_BASE_WORKING_PATH = "/workspace/sandboxes"
_DEFAULT_SSH_CONNECT_TIMEOUT_SECONDS = 10
_DEFAULT_SSH_OPERATION_TIMEOUT_SECONDS = 30
_DEFAULT_COMMAND_MAX_RUNTIME_SECONDS = 60 * 60
_SSH_CONNECT_TIMEOUT_SECONDS = 10
_SSH_OPERATION_TIMEOUT_SECONDS = 30
_COMMAND_TIMEOUT_EXIT_CODE = 124
class OptionsKey(StrEnum):
@ -150,7 +150,7 @@ class SSHSandboxEnvironment(VirtualEnvironment):
raise RuntimeError("SSH transport is not available")
channel = transport.open_session()
channel.settimeout(self._DEFAULT_SSH_OPERATION_TIMEOUT_SECONDS)
channel.settimeout(self._SSH_OPERATION_TIMEOUT_SECONDS)
channel.set_combine_stderr(False)
execution_command = self._build_exec_command(command, environments, cwd)
@ -166,7 +166,7 @@ class SSHSandboxEnvironment(VirtualEnvironment):
threading.Thread(
target=self._consume_channel_output,
args=(pid, channel, stdout_transport, stderr_transport, self._DEFAULT_COMMAND_MAX_RUNTIME_SECONDS),
args=(pid, channel, stdout_transport, stderr_transport, COMMAND_EXECUTION_TIMEOUT_SECONDS),
daemon=True,
).start()
@ -274,9 +274,9 @@ class SSHSandboxEnvironment(VirtualEnvironment):
password=password,
look_for_keys=False,
allow_agent=False,
timeout=cls._DEFAULT_SSH_CONNECT_TIMEOUT_SECONDS,
banner_timeout=cls._DEFAULT_SSH_CONNECT_TIMEOUT_SECONDS,
auth_timeout=cls._DEFAULT_SSH_CONNECT_TIMEOUT_SECONDS,
timeout=cls._SSH_CONNECT_TIMEOUT_SECONDS,
banner_timeout=cls._SSH_CONNECT_TIMEOUT_SECONDS,
auth_timeout=cls._SSH_CONNECT_TIMEOUT_SECONDS,
)
transport = client.get_transport()
if transport is not None:
@ -361,15 +361,15 @@ class SSHSandboxEnvironment(VirtualEnvironment):
@classmethod
def _run_command(cls, client: Any, command: str) -> bytes:
_, stdout, stderr = client.exec_command(command, timeout=cls._DEFAULT_SSH_OPERATION_TIMEOUT_SECONDS)
stdout.channel.settimeout(cls._DEFAULT_SSH_OPERATION_TIMEOUT_SECONDS)
_, stdout, stderr = client.exec_command(command, timeout=cls._SSH_OPERATION_TIMEOUT_SECONDS)
stdout.channel.settimeout(cls._SSH_OPERATION_TIMEOUT_SECONDS)
deadline = time.monotonic() + cls._DEFAULT_COMMAND_MAX_RUNTIME_SECONDS
deadline = time.monotonic() + COMMAND_EXECUTION_TIMEOUT_SECONDS
while not stdout.channel.exit_status_ready():
if time.monotonic() >= deadline:
with contextlib.suppress(Exception):
stdout.channel.close()
raise TimeoutError(f"SSH command timed out after {cls._DEFAULT_COMMAND_MAX_RUNTIME_SECONDS}s")
raise TimeoutError(f"SSH command timed out after {COMMAND_EXECUTION_TIMEOUT_SECONDS}s")
time.sleep(0.05)
exit_code = stdout.channel.recv_exit_status()
@ -428,7 +428,7 @@ class SSHSandboxEnvironment(VirtualEnvironment):
def _set_sftp_operation_timeout(self, sftp: Any) -> None:
with contextlib.suppress(Exception):
sftp.get_channel().settimeout(self._DEFAULT_SSH_OPERATION_TIMEOUT_SECONDS)
sftp.get_channel().settimeout(self._SSH_OPERATION_TIMEOUT_SECONDS)
@staticmethod
def _parse_arch(raw_arch: str) -> Arch: