fix(gateway): force exit after graceful shutdown

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
LeonSGP43 2026-06-26 23:13:35 +08:00 committed by Teknium
parent dddaea0c98
commit 9f0e64cedd
2 changed files with 72 additions and 4 deletions

View file

@ -18689,11 +18689,21 @@ def main():
data = yaml.safe_load(f) or {}
config = GatewayConfig.from_dict(data)
# Run the gateway - exit with code 1 if no platforms connected,
# so systemd Restart=on-failure will retry on transient errors (e.g. DNS)
# start_gateway() already performs graceful teardown before returning.
# Force-exit afterwards so a wedged non-daemon worker thread cannot block
# interpreter finalization and strand the gateway half-shut down.
success = asyncio.run(start_gateway(config))
if not success:
sys.exit(1)
_exit_after_graceful_shutdown(success)
def _exit_after_graceful_shutdown(success: bool) -> None:
"""Flush stdio and terminate immediately after graceful shutdown."""
for stream in (sys.stdout, sys.stderr):
try:
stream.flush()
except Exception:
pass
os._exit(0 if success else 1)
if __name__ == "__main__":

View file

@ -0,0 +1,58 @@
from types import SimpleNamespace
from unittest.mock import Mock
import pytest
import gateway.run as gateway_run
class _ExitCalled(Exception):
def __init__(self, code: int):
super().__init__(code)
self.code = code
def _raise_exit(code: int) -> None:
raise _ExitCalled(code)
def test_main_force_exits_zero_after_clean_shutdown(monkeypatch):
async def fake_start_gateway(config=None):
return True
stdout = SimpleNamespace(flush=Mock())
stderr = SimpleNamespace(flush=Mock())
monkeypatch.setattr(gateway_run, "start_gateway", fake_start_gateway)
monkeypatch.setattr(gateway_run.os, "_exit", _raise_exit)
monkeypatch.setattr(gateway_run.sys, "argv", ["gateway.run"])
monkeypatch.setattr(gateway_run.sys, "stdout", stdout)
monkeypatch.setattr(gateway_run.sys, "stderr", stderr)
with pytest.raises(_ExitCalled) as exc_info:
gateway_run.main()
assert exc_info.value.code == 0
stdout.flush.assert_called_once_with()
stderr.flush.assert_called_once_with()
def test_main_force_exits_one_after_failed_shutdown(monkeypatch):
async def fake_start_gateway(config=None):
return False
stdout = SimpleNamespace(flush=Mock())
stderr = SimpleNamespace(flush=Mock())
monkeypatch.setattr(gateway_run, "start_gateway", fake_start_gateway)
monkeypatch.setattr(gateway_run.os, "_exit", _raise_exit)
monkeypatch.setattr(gateway_run.sys, "argv", ["gateway.run"])
monkeypatch.setattr(gateway_run.sys, "stdout", stdout)
monkeypatch.setattr(gateway_run.sys, "stderr", stderr)
with pytest.raises(_ExitCalled) as exc_info:
gateway_run.main()
assert exc_info.value.code == 1
stdout.flush.assert_called_once_with()
stderr.flush.assert_called_once_with()