diff --git a/setup.py b/setup.py index b890834e7..ac4373cae 100644 --- a/setup.py +++ b/setup.py @@ -79,7 +79,9 @@ license='BSD-derived (http://www.repoze.org/LICENSE.txt)', url='http://supervisord.org/', project_urls={ - 'Changelog': 'http://supervisord.org/changes.html', + 'Changelog': 'http://supervisord.org/changelog', + 'Documentation': 'http://supervisord.org', + 'Issue Tracker': 'https://github.com/Supervisor/supervisor', }, description="A system for controlling process state under UNIX", long_description=README + '\n\n' + CHANGES, diff --git a/supervisor/process.py b/supervisor/process.py index b394be812..10d353947 100644 --- a/supervisor/process.py +++ b/supervisor/process.py @@ -739,7 +739,19 @@ def spawn(self): """ Overrides Subprocess.spawn() so we can hook in before it happens """ - self.before_spawn() + try: + self.before_spawn() + except NotImplementedError: + raise + except BaseException as e: + if hasattr(self, 'group') and hasattr(self.group, 'socket_manager'): + self.record_spawnerr('Could not create FastCGI socket %s: %s' % ( + self.group.socket_manager.config(), e)) + else: + self.record_spawnerr(e.args[0]) + self.change_state(ProcessStates.BACKOFF) + self.give_up() + return pid = Subprocess.spawn(self) if pid is None: #Remove object reference to decrement the reference count on error diff --git a/supervisor/tests/test_process.py b/supervisor/tests/test_process.py index d9370e24c..cd9e49961 100644 --- a/supervisor/tests/test_process.py +++ b/supervisor/tests/test_process.py @@ -20,7 +20,7 @@ from supervisor.tests.base import DummyProcessGroup from supervisor.tests.base import DummyFCGIProcessGroup -from supervisor.process import Subprocess +from supervisor.process import Subprocess, ProcessStates from supervisor.options import BadCommand class SubprocessTests(unittest.TestCase): @@ -1799,6 +1799,18 @@ def test_before_spawn_gets_socket_ref(self): instance.before_spawn() self.assertFalse(instance.fcgi_sock is None) + def test_before_spawn_failure_sets_fatal_state(self): + options = DummyOptions() + config = DummyPConfig(options, 'good', '/good/filename', uid=1) + instance = self._makeOne(config) + instance.group = Mock() + socket_manager = Mock() + instance.group.attach_mock(socket_manager, 'socket_manager') + socket_manager.attach_mock(Mock(side_effect=Exception), 'get_socket') + self.assertEqual(instance.state, ProcessStates.STOPPED) + instance.spawn() + self.assertEqual(instance.state, ProcessStates.FATAL) + def test_after_finish_removes_socket_ref(self): options = DummyOptions() config = DummyPConfig(options, 'good', '/good/filename', uid=1)