mirror of
https://github.com/frappe/gunicorn.git
synced 2026-01-14 11:09:11 +08:00
Add child_exit() callback
This is similar to worker_exit() in that it is called just after a worker has terminated, but it's called in the Gunicorn *master* process, not the *child* process.
This commit is contained in:
parent
b3c4260706
commit
53fd1c1071
@ -498,8 +498,9 @@ class Arbiter(object):
|
||||
if self.reexec_pid == wpid:
|
||||
self.reexec_pid = 0
|
||||
else:
|
||||
# A worker said it cannot boot. We'll shutdown
|
||||
# to avoid infinite start/stop cycles.
|
||||
# A worker was terminated. If the termination reason was
|
||||
# that it could not boot, we'll shut it down to avoid
|
||||
# infinite start/stop cycles.
|
||||
exitcode = status >> 8
|
||||
if exitcode == self.WORKER_BOOT_ERROR:
|
||||
reason = "Worker failed to boot."
|
||||
@ -507,10 +508,12 @@ class Arbiter(object):
|
||||
if exitcode == self.APP_LOAD_ERROR:
|
||||
reason = "App failed to load."
|
||||
raise HaltServer(reason, self.APP_LOAD_ERROR)
|
||||
|
||||
worker = self.WORKERS.pop(wpid, None)
|
||||
if not worker:
|
||||
continue
|
||||
worker.tmp.close()
|
||||
self.cfg.child_exit(self, worker)
|
||||
except OSError as e:
|
||||
if e.errno != errno.ECHILD:
|
||||
raise
|
||||
|
||||
@ -1634,6 +1634,23 @@ class PostRequest(Setting):
|
||||
"""
|
||||
|
||||
|
||||
class ChildExit(Setting):
|
||||
name = "child_exit"
|
||||
section = "Server Hooks"
|
||||
validator = validate_callable(2)
|
||||
type = six.callable
|
||||
|
||||
def child_exit(server, worker):
|
||||
pass
|
||||
default = staticmethod(child_exit)
|
||||
desc = """\
|
||||
Called just after a worker has been exited, in the master process.
|
||||
|
||||
The callable needs to accept two instance variables for the Arbiter and
|
||||
the just-exited Worker.
|
||||
"""
|
||||
|
||||
|
||||
class WorkerExit(Setting):
|
||||
name = "worker_exit"
|
||||
section = "Server Hooks"
|
||||
@ -1644,7 +1661,7 @@ class WorkerExit(Setting):
|
||||
pass
|
||||
default = staticmethod(worker_exit)
|
||||
desc = """\
|
||||
Called just after a worker has been exited.
|
||||
Called just after a worker has been exited, in the worker process.
|
||||
|
||||
The callable needs to accept two instance variables for the Arbiter and
|
||||
the just-exited Worker.
|
||||
|
||||
@ -55,6 +55,18 @@ def test_arbiter_calls_worker_exit(mock_os_fork):
|
||||
arbiter.cfg.worker_exit.assert_called_with(arbiter, mock_worker)
|
||||
|
||||
|
||||
@mock.patch('os.waitpid')
|
||||
def test_arbiter_reap_workers(mock_os_waitpid):
|
||||
mock_os_waitpid.side_effect = [(42, 0), (0, 0)]
|
||||
arbiter = gunicorn.arbiter.Arbiter(DummyApplication())
|
||||
arbiter.cfg.settings['child_exit'] = mock.Mock()
|
||||
mock_worker = mock.Mock()
|
||||
arbiter.WORKERS = {42: mock_worker}
|
||||
arbiter.reap_workers()
|
||||
mock_worker.tmp.close.assert_called_with()
|
||||
arbiter.cfg.child_exit.assert_called_with(arbiter, mock_worker)
|
||||
|
||||
|
||||
class PreloadedAppWithEnvSettings(DummyApplication):
|
||||
"""
|
||||
Simple application that makes use of the 'preload' feature to
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user