From d78a84dc692f708afd90df3409f9e264c22231dd Mon Sep 17 00:00:00 2001 From: Giao Le Date: Tue, 22 Nov 2016 10:18:14 -0500 Subject: [PATCH 1/1] add worker abort hook --- gunicorn/arbiter.py | 9 +++++++-- gunicorn/config.py | 18 ++++++++++++++++++ gunicorn/workers/base.py | 7 +++++++ 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/gunicorn/arbiter.py b/gunicorn/arbiter.py index b48e5b7..4d2daad 100644 --- a/gunicorn/arbiter.py +++ b/gunicorn/arbiter.py @@ -429,8 +429,13 @@ class Arbiter(object): except ValueError: continue - self.log.critical("WORKER TIMEOUT (pid:%s)", pid) - self.kill_worker(pid, signal.SIGKILL) + if not worker.aborted: + self.log.critical("WORKER TIMEOUT (pid:%s)", pid) + worker.aborted = True + self.kill_worker(pid, signal.SIGABRT) + else: + self.kill_worker(pid, signal.SIGKILL) + def reap_workers(self): """\ diff --git a/gunicorn/config.py b/gunicorn/config.py index efcc449..3aec7ae 100644 --- a/gunicorn/config.py +++ b/gunicorn/config.py @@ -1282,6 +1282,24 @@ class PostWorkerInit(Setting): """ +class WorkerAbort(Setting): + name = "worker_abort" + section = "Server Hooks" + validator = validate_callable(1) + type = six.callable + + def worker_abort(worker): + pass + + default = staticmethod(worker_abort) + desc = """\ + Called when a worker received the SIGABRT signal. + This call generally happens on timeout. + The callable needs to accept one instance variable for the initialized + Worker. + """ + + class PreExec(Setting): name = "pre_exec" section = "Server Hooks" diff --git a/gunicorn/workers/base.py b/gunicorn/workers/base.py index 5566dd1..af785a1 100644 --- a/gunicorn/workers/base.py +++ b/gunicorn/workers/base.py @@ -40,6 +40,7 @@ class Worker(object): self.timeout = timeout self.cfg = cfg self.booted = False + self.aborted = False self.nr = 0 self.max_requests = cfg.max_requests or MAXSIZE @@ -120,6 +121,7 @@ class Worker(object): signal.signal(signal.SIGINT, self.handle_exit) signal.signal(signal.SIGWINCH, self.handle_winch) signal.signal(signal.SIGUSR1, self.handle_usr1) + signal.signal(signal.SIGABRT, self.handle_abort) # Don't let SIGQUIT and SIGUSR1 disturb active requests # by interrupting system calls if hasattr(signal, 'siginterrupt'): # python >= 2.6 @@ -202,3 +204,8 @@ class Worker(object): def handle_winch(self, sig, fname): # Ignore SIGWINCH in worker. Fixes a crash on OpenBSD. return + + def handle_abort(self, sig, frame): + self.alive = False + self.cfg.worker_abort(self) + sys.exit(1) -- 1.8.3.1