diff --git a/supervisor/process.py b/supervisor/process.py index 38c03504c..d6f60f3e2 100644 --- a/supervisor/process.py +++ b/supervisor/process.py @@ -512,7 +512,18 @@ def signal(self, sig): ProcessStates.STOPPING) try: - options.kill(self.pid, sig) + try: + options.kill(self.pid, sig) + except OSError as exc: + if exc.errno == errno.ESRCH: + msg = ("unable to signal %s (pid %s), it probably just now exited " + "on its own: %s" % (processname, self.pid, + str(exc))) + options.logger.debug(msg) + # we could change the state here but we intentionally do + # not. we will do it during normal SIGCHLD processing. + return None + raise except: tb = traceback.format_exc() msg = 'unknown problem sending sig %s (%s):%s' % ( diff --git a/supervisor/tests/test_process.py b/supervisor/tests/test_process.py index 1a23ae62b..bc9ade41c 100644 --- a/supervisor/tests/test_process.py +++ b/supervisor/tests/test_process.py @@ -1004,6 +1004,29 @@ def test_signal_from_running(self): self.assertTrue(instance.pid in options.kills) self.assertEqual(options.kills[instance.pid], signal.SIGWINCH) + def test_signal_from_running_error_ESRCH(self): + options = DummyOptions() + config = DummyPConfig(options, 'test', '/test') + options.kill_exception = OSError(errno.ESRCH, + os.strerror(errno.ESRCH)) + instance = self._makeOne(config) + L = [] + from supervisor.states import ProcessStates + from supervisor import events + events.subscribe(events.ProcessStateEvent, lambda x: L.append(x)) + instance.pid = 11 + instance.state = ProcessStates.RUNNING + instance.signal(signal.SIGWINCH) + self.assertEqual(options.logger.data[0], + 'sending test (pid 11) sig SIGWINCH') + self.assertEqual(options.logger.data[1], 'unable to signal test (pid 11), ' + 'it probably just now exited on its own: %s' % + str(options.kill_exception)) + self.assertFalse(instance.killing) + self.assertEqual(instance.state, ProcessStates.RUNNING) # unchanged + self.assertEqual(instance.pid, 11) # unchanged + self.assertEqual(len(L), 0) + def test_signal_from_running_error(self): options = DummyOptions() config = DummyPConfig(options, 'test', '/test')