Merge pull request #768 from benoitc/feature/abort

try to log what happened in the worker after a timeout.
This commit is contained in:
Randall Leeds 2014-06-01 10:11:45 -07:00
commit eff6c08935
5 changed files with 59 additions and 3 deletions

View File

@ -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
View 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])

View File

@ -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):
"""\

View File

@ -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"

View File

@ -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