Skip to content

Commit

Permalink
Handle race where process exits immediately in signal()
Browse files Browse the repository at this point in the history
  • Loading branch information
mnaberez committed Feb 23, 2021
1 parent d0026ae commit 0c66c0c
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 1 deletion.
13 changes: 12 additions & 1 deletion supervisor/process.py
Original file line number Diff line number Diff line change
Expand Up @@ -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' % (
Expand Down
23 changes: 23 additions & 0 deletions supervisor/tests/test_process.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down

0 comments on commit 0c66c0c

Please sign in to comment.