From f0e5166f9141e1c2539651de36ba71f50531f3d1 Mon Sep 17 00:00:00 2001 From: Adam Hopkins Date: Sun, 18 Dec 2022 13:32:53 +0200 Subject: [PATCH] Fix double ctrl-c kill --- sanic/worker/manager.py | 8 ++++---- tests/worker/test_manager.py | 20 ++++++++++++++++++-- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/sanic/worker/manager.py b/sanic/worker/manager.py index 2f09b818c1..5636169e24 100644 --- a/sanic/worker/manager.py +++ b/sanic/worker/manager.py @@ -38,7 +38,7 @@ def __init__( self.monitor_publisher, self.monitor_subscriber = monitor_pubsub self.worker_state = worker_state self.worker_state["Sanic-Main"] = {"pid": self.pid} - self.terminated = False + self._shutting_down = False self._serve = serve self._server_settings = server_settings self._server_count = count() @@ -114,10 +114,9 @@ def join(self): self.join() def terminate(self): - if not self.terminated: + if not self._shutting_down: for process in self.processes: process.terminate() - self.terminated = True def restart(self, process_names: Optional[List[str]] = None, **kwargs): for process in self.transient_processes: @@ -238,7 +237,7 @@ def kill(self): raise ServerKilled def shutdown_signal(self, signal, frame): - if self.terminated: + if self._shutting_down: logger.info("Shutdown interrupted. Killing.") with suppress(ServerKilled): self.kill() @@ -251,6 +250,7 @@ def shutdown(self): for process in self.processes: if process.is_alive(): process.terminate() + self._shutting_down = True @property def pid(self): diff --git a/tests/worker/test_manager.py b/tests/worker/test_manager.py index 85f673dd81..d5c40665b8 100644 --- a/tests/worker/test_manager.py +++ b/tests/worker/test_manager.py @@ -32,9 +32,7 @@ def test_terminate(os_mock: Mock): context = Mock() context.Process.return_value = process manager = WorkerManager(1, fake_serve, {}, context, (Mock(), Mock()), {}) - assert manager.terminated is False manager.terminate() - assert manager.terminated is True os_mock.kill.assert_called_once_with(1234, SIGINT) @@ -62,6 +60,24 @@ def test_kill(os_mock: Mock): os_mock.kill.assert_called_once_with(1234, SIGKILL) +@patch("sanic.worker.process.os") +@patch("sanic.worker.manager.os") +def test_shutdown_signal_send_kill( + manager_os_mock: Mock, process_os_mock: Mock +): + process = Mock() + process.pid = 1234 + context = Mock() + context.Process.return_value = process + manager = WorkerManager(1, fake_serve, {}, context, (Mock(), Mock()), {}) + assert manager._shutting_down is False + manager.shutdown_signal(SIGINT, None) + assert manager._shutting_down is True + process_os_mock.kill.assert_called_once_with(1234, SIGINT) + manager.shutdown_signal(SIGINT, None) + manager_os_mock.kill.assert_called_once_with(1234, SIGKILL) + + def test_restart_all(): p1 = Mock() p2 = Mock()