From 4afd479f51631ea39f8403df6b1e0467fc81c466 Mon Sep 17 00:00:00 2001 From: bird <6666242+bird@users.noreply.github.com> Date: Wed, 13 May 2026 16:06:06 -0400 Subject: [PATCH] fix(gateway): use service restart path in Docker/Podman containers The /restart command used a detached subprocess approach to restart the gateway. In Docker, when the gateway process exits, tini (PID 1) also exits, causing Docker to stop the container and kill the detached helper before it can restart the gateway. This made /restart effectively a /shutdown in containerized deployments. Detect Docker (/.dockerenv) and Podman (/run/.containerenv) containers and use the service restart path (exit code 75) instead, letting the container restart policy handle the actual restart. Note: requires restart policy that restarts on non-zero exit (e.g. unless-stopped or on-failure). --- gateway/run.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/gateway/run.py b/gateway/run.py index db7066281c3..a0ab84e850d 100644 --- a/gateway/run.py +++ b/gateway/run.py @@ -8971,13 +8971,15 @@ class GatewayRunner: logger.debug("Failed to write restart dedup marker: %s", e) active_agents = self._running_agent_count() - # When running under a service manager (systemd/launchd), use the - # service restart path: exit with code 75 so the service manager - # restarts us. The detached subprocess approach (setsid + bash) - # doesn't work under systemd because KillMode=mixed kills all - # processes in the cgroup, including the detached helper. + # When running under a service manager (systemd/launchd) or inside a + # Docker/Podman container, use the service restart path: exit with + # code 75 so the service manager / container restart policy restarts + # us. The detached subprocess approach (setsid + bash) doesn't work + # under systemd (KillMode=mixed kills the cgroup) or Docker (tini + # exits when the gateway dies, taking the detached helper with it). _under_service = bool(os.environ.get("INVOCATION_ID")) # systemd sets this - if _under_service: + _in_container = os.path.exists("/.dockerenv") or os.path.exists("/run/.containerenv") + if _under_service or _in_container: self.request_restart(detached=False, via_service=True) else: self.request_restart(detached=True, via_service=False)