fix(gateway): handle lifecycle edge cases
This commit is contained in:
+13
-13
@@ -178,7 +178,8 @@ class GatewayRuntime:
|
||||
self._clear_state()
|
||||
return RuntimeResult(False, "gateway_state_stale", self.status(reason="stale_state"))
|
||||
|
||||
self._terminate(status.pid, timeout_s=timeout_s)
|
||||
if not self._terminate(status.pid, timeout_s=timeout_s):
|
||||
return RuntimeResult(False, "gateway_stop_timeout", self.status(reason="stop_timeout"))
|
||||
self._clear_state()
|
||||
return RuntimeResult(True, "gateway_stopped", self.status(reason="stopped"))
|
||||
|
||||
@@ -263,13 +264,12 @@ class GatewayRuntime:
|
||||
return {"creationflags": flags}
|
||||
return {"start_new_session": True}
|
||||
|
||||
def _terminate(self, pid: int, *, timeout_s: int) -> None:
|
||||
def _terminate(self, pid: int, *, timeout_s: int) -> bool:
|
||||
if self.platform_name == "Windows":
|
||||
self._terminate_windows(pid, timeout_s=timeout_s)
|
||||
else:
|
||||
self._terminate_posix(pid, timeout_s=timeout_s)
|
||||
return self._terminate_windows(pid, timeout_s=timeout_s)
|
||||
return self._terminate_posix(pid, timeout_s=timeout_s)
|
||||
|
||||
def _terminate_posix(self, pid: int, *, timeout_s: int) -> None:
|
||||
def _terminate_posix(self, pid: int, *, timeout_s: int) -> bool:
|
||||
try:
|
||||
pgid = os.getpgid(pid)
|
||||
except OSError:
|
||||
@@ -280,28 +280,28 @@ class GatewayRuntime:
|
||||
else:
|
||||
os.kill(pid, signal.SIGTERM)
|
||||
except ProcessLookupError:
|
||||
return
|
||||
return True
|
||||
if self._wait_for_exit(pid, timeout_s):
|
||||
return
|
||||
return True
|
||||
with suppress(ProcessLookupError):
|
||||
if pgid is not None:
|
||||
os.killpg(pgid, signal.SIGKILL)
|
||||
else:
|
||||
os.kill(pid, signal.SIGKILL)
|
||||
self._wait_for_exit(pid, 2)
|
||||
return self._wait_for_exit(pid, 2)
|
||||
|
||||
def _terminate_windows(self, pid: int, *, timeout_s: int) -> None:
|
||||
def _terminate_windows(self, pid: int, *, timeout_s: int) -> bool:
|
||||
ctrl_break = getattr(signal, "CTRL_BREAK_EVENT", None)
|
||||
if ctrl_break is not None:
|
||||
with suppress(ProcessLookupError):
|
||||
os.kill(pid, ctrl_break)
|
||||
if self._wait_for_exit(pid, timeout_s):
|
||||
return
|
||||
return True
|
||||
self._subprocess_run(["taskkill", "/PID", str(pid), "/T"], check=False)
|
||||
if self._wait_for_exit(pid, 2):
|
||||
return
|
||||
return True
|
||||
self._subprocess_run(["taskkill", "/PID", str(pid), "/T", "/F"], check=False)
|
||||
self._wait_for_exit(pid, 2)
|
||||
return self._wait_for_exit(pid, 2)
|
||||
|
||||
def _wait_for_exit(self, pid: int, timeout_s: int | float) -> bool:
|
||||
deadline = time.monotonic() + max(float(timeout_s), 0.0)
|
||||
|
||||
@@ -141,7 +141,7 @@ class GatewayServiceInstaller:
|
||||
"Label": label,
|
||||
"ProgramArguments": build_gateway_command(options.python_executable, options.start),
|
||||
"WorkingDirectory": _working_directory_text(options.start),
|
||||
"RunAtLoad": bool(options.start_now),
|
||||
"RunAtLoad": bool(options.enable),
|
||||
"KeepAlive": {"SuccessfulExit": False},
|
||||
"StandardOutPath": str(stdout_path),
|
||||
"StandardErrorPath": str(stderr_path),
|
||||
@@ -149,7 +149,7 @@ class GatewayServiceInstaller:
|
||||
content = plistlib.dumps(payload, sort_keys=False).decode("utf-8")
|
||||
domain = _launchd_domain()
|
||||
commands: list[tuple[str, ...]] = []
|
||||
if options.enable or options.start_now:
|
||||
if options.start_now:
|
||||
commands.append(("launchctl", "bootstrap", domain, str(path)))
|
||||
if options.enable:
|
||||
commands.append(("launchctl", "enable", f"{domain}/{label}"))
|
||||
@@ -162,7 +162,7 @@ class GatewayServiceInstaller:
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
stdout_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(content, encoding="utf-8")
|
||||
if options.enable or options.start_now:
|
||||
if options.start_now:
|
||||
self._run_best_effort(("launchctl", "bootout", domain, str(path)))
|
||||
for command_args in commands:
|
||||
self._subprocess_run(list(command_args), check=True)
|
||||
|
||||
Reference in New Issue
Block a user