Make TUI quit instant by SIGKILL-ing the sandbox container (#548)
This commit is contained in:
@@ -751,7 +751,7 @@ class StrixTUIApp(App): # type: ignore[misc]
|
|||||||
self.report_state.cleanup()
|
self.report_state.cleanup()
|
||||||
|
|
||||||
def signal_handler(_signum: int, _frame: Any) -> None:
|
def signal_handler(_signum: int, _frame: Any) -> None:
|
||||||
self._teardown_sandbox_blocking(timeout=10.0)
|
self._fire_sandbox_cleanup()
|
||||||
self.report_state.cleanup(status="interrupted")
|
self.report_state.cleanup(status="interrupted")
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
@@ -1705,36 +1705,24 @@ class StrixTUIApp(App): # type: ignore[misc]
|
|||||||
)
|
)
|
||||||
|
|
||||||
async def action_custom_quit(self) -> None:
|
async def action_custom_quit(self) -> None:
|
||||||
await asyncio.to_thread(self._teardown_sandbox_blocking, timeout=10.0)
|
self._fire_sandbox_cleanup()
|
||||||
|
|
||||||
if self._scan_thread and self._scan_thread.is_alive():
|
if self._scan_thread and self._scan_thread.is_alive():
|
||||||
self._scan_stop_event.set()
|
self._scan_stop_event.set()
|
||||||
self._scan_thread.join(timeout=2.0)
|
|
||||||
|
|
||||||
self.report_state.cleanup()
|
self.report_state.cleanup()
|
||||||
|
|
||||||
self.exit()
|
self.exit()
|
||||||
|
|
||||||
def _teardown_sandbox_blocking(self, *, timeout: float) -> None:
|
def _fire_sandbox_cleanup(self) -> None:
|
||||||
loop = self._scan_loop
|
loop = self._scan_loop
|
||||||
if loop is None or loop.is_closed():
|
if loop is None or loop.is_closed():
|
||||||
return
|
return
|
||||||
run_name = self.scan_config.get("run_name")
|
run_name = self.scan_config.get("run_name")
|
||||||
if not run_name:
|
if not run_name:
|
||||||
return
|
return
|
||||||
future = asyncio.run_coroutine_threadsafe(
|
with contextlib.suppress(Exception):
|
||||||
session_manager.cleanup(run_name),
|
asyncio.run_coroutine_threadsafe(session_manager.cleanup(run_name), loop)
|
||||||
loop,
|
|
||||||
)
|
|
||||||
try:
|
|
||||||
future.result(timeout=timeout)
|
|
||||||
except TimeoutError:
|
|
||||||
logger.warning(
|
|
||||||
"Sandbox cleanup timed out after %.1fs; container may still be running",
|
|
||||||
timeout,
|
|
||||||
)
|
|
||||||
except Exception:
|
|
||||||
logger.exception("Sandbox cleanup failed")
|
|
||||||
|
|
||||||
def _is_widget_safe(self, widget: Any) -> bool:
|
def _is_widget_safe(self, widget: Any) -> bool:
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ re-merging the parent body. Track upstream for an injection hook.
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import contextlib
|
||||||
import logging
|
import logging
|
||||||
import uuid
|
import uuid
|
||||||
from typing import Any
|
from typing import Any
|
||||||
@@ -34,6 +35,8 @@ from agents.sandbox.sandboxes.docker import (
|
|||||||
_manifest_requires_fuse,
|
_manifest_requires_fuse,
|
||||||
_manifest_requires_sys_admin,
|
_manifest_requires_sys_admin,
|
||||||
)
|
)
|
||||||
|
from agents.sandbox.session.sandbox_session import SandboxSession
|
||||||
|
from docker import errors as docker_errors # type: ignore[import-untyped, unused-ignore]
|
||||||
from docker.models.containers import Container # type: ignore[import-untyped, unused-ignore]
|
from docker.models.containers import Container # type: ignore[import-untyped, unused-ignore]
|
||||||
from docker.utils import parse_repository_tag # type: ignore[import-untyped, unused-ignore]
|
from docker.utils import parse_repository_tag # type: ignore[import-untyped, unused-ignore]
|
||||||
|
|
||||||
@@ -121,3 +124,10 @@ class StrixDockerSandboxClient(DockerSandboxClient):
|
|||||||
image,
|
image,
|
||||||
)
|
)
|
||||||
return container
|
return container
|
||||||
|
|
||||||
|
async def delete(self, session: SandboxSession) -> SandboxSession:
|
||||||
|
container_id = getattr(getattr(session._inner, "state", None), "container_id", None)
|
||||||
|
if container_id:
|
||||||
|
with contextlib.suppress(docker_errors.NotFound, docker_errors.APIError):
|
||||||
|
self.docker_client.containers.get(container_id).kill()
|
||||||
|
return await super().delete(session)
|
||||||
|
|||||||
Reference in New Issue
Block a user