diff --git a/mitogen/parent.py b/mitogen/parent.py index 56dbc31f..36ecb295 100644 --- a/mitogen/parent.py +++ b/mitogen/parent.py @@ -699,7 +699,11 @@ class Stream(mitogen.core.Stream): LOG.debug('%r.connect(): child process stdin/stdout=%r', self, self.receive_side.fd) - self._connect_bootstrap(extra_fd) + try: + self._connect_bootstrap(extra_fd) + except Exception: + self._reap_child() + raise def _ec0_received(self): LOG.debug('%r._ec0_received()', self) diff --git a/tests/data/python_never_responds.sh b/tests/data/python_never_responds.sh new file mode 100755 index 00000000..f1ad5787 --- /dev/null +++ b/tests/data/python_never_responds.sh @@ -0,0 +1,3 @@ +#!/bin/bash +# I am a Python interpreter that sits idle until the connection times out. +exec -a mitogen-tests-python-never-responds.sh sleep 86400 diff --git a/tests/parent_test.py b/tests/parent_test.py index 590380cd..ec74eb3f 100644 --- a/tests/parent_test.py +++ b/tests/parent_test.py @@ -1,3 +1,4 @@ +import errno import os import subprocess import tempfile @@ -9,6 +10,26 @@ import testlib import mitogen.parent +class ReapChildTest(testlib.RouterMixin, testlib.TestCase): + def test_connect_timeout(self): + # Ensure the child process is reaped if the connection times out. + stream = mitogen.parent.Stream( + router=self.router, + remote_id=1234, + old_router=self.router, + max_message_size=self.router.max_message_size, + python_path=testlib.data_path('python_never_responds.sh'), + connect_timeout=0.5, + ) + self.assertRaises(mitogen.core.TimeoutError, + lambda: stream.connect() + ) + e = self.assertRaises(OSError, + lambda: os.kill(stream.pid, 0) + ) + self.assertEquals(e.args[0], errno.ESRCH) + + class StreamErrorTest(testlib.RouterMixin, testlib.TestCase): def test_direct_eof(self): e = self.assertRaises(mitogen.core.StreamError,