mirror of
https://github.com/frappe/gunicorn.git
synced 2026-01-14 11:09:11 +08:00
Merge pull request #768 from benoitc/feature/abort
try to log what happened in the worker after a timeout.
This commit is contained in:
commit
eff6c08935
@ -217,3 +217,6 @@ def worker_int(worker):
|
||||
if line:
|
||||
code.append(" %s" % (line.strip()))
|
||||
worker.log.debug("\n".join(code))
|
||||
|
||||
def worker_abort(worker):
|
||||
worker.log.info("worker received SIGABRT signal")
|
||||
|
||||
21
examples/timeout.py
Normal file
21
examples/timeout.py
Normal file
@ -0,0 +1,21 @@
|
||||
# -*- coding: utf-8 -
|
||||
#
|
||||
# This file is part of gunicorn released under the MIT license.
|
||||
# See the NOTICE for more information.
|
||||
|
||||
import sys
|
||||
import time
|
||||
|
||||
|
||||
def app(environ, start_response):
|
||||
"""Application which cooperatively pauses 10 seconds before responding"""
|
||||
data = b'Hello, World!\n'
|
||||
status = '200 OK'
|
||||
response_headers = [
|
||||
('Content-type','text/plain'),
|
||||
('Content-Length', str(len(data))) ]
|
||||
sys.stdout.write('request will timeout')
|
||||
sys.stdout.flush()
|
||||
time.sleep(35)
|
||||
start_response(status, response_headers)
|
||||
return iter([data])
|
||||
@ -433,8 +433,12 @@ 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):
|
||||
"""\
|
||||
|
||||
@ -1336,6 +1336,26 @@ class WorkerInt(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 happen on timeout.
|
||||
|
||||
The callable needs to accept one instance variable for the initialized
|
||||
Worker.
|
||||
"""
|
||||
|
||||
|
||||
class PreExec(Setting):
|
||||
name = "pre_exec"
|
||||
section = "Server Hooks"
|
||||
|
||||
@ -23,7 +23,7 @@ from gunicorn.six import MAXSIZE
|
||||
class Worker(object):
|
||||
|
||||
SIGNALS = [getattr(signal, "SIG%s" % x) \
|
||||
for x in "HUP QUIT INT TERM USR1 USR2 WINCH CHLD".split()]
|
||||
for x in "ABRT HUP QUIT INT TERM USR1 USR2 WINCH CHLD".split()]
|
||||
|
||||
PIPE = []
|
||||
|
||||
@ -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
|
||||
@ -127,6 +128,8 @@ class Worker(object):
|
||||
signal.signal(signal.SIGINT, self.handle_quit)
|
||||
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
|
||||
@ -145,6 +148,11 @@ class Worker(object):
|
||||
self.alive = False
|
||||
sys.exit(0)
|
||||
|
||||
def handle_abort(self, sig, frame):
|
||||
self.alive = False
|
||||
self.cfg.worker_abort(self)
|
||||
sys.exit(1)
|
||||
|
||||
def handle_error(self, req, client, addr, exc):
|
||||
request_start = datetime.now()
|
||||
addr = addr or ('', -1) # unix socket case
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user