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:
|
if line:
|
||||||
code.append(" %s" % (line.strip()))
|
code.append(" %s" % (line.strip()))
|
||||||
worker.log.debug("\n".join(code))
|
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:
|
except ValueError:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
self.log.critical("WORKER TIMEOUT (pid:%s)", pid)
|
if not worker.aborted:
|
||||||
self.kill_worker(pid, signal.SIGKILL)
|
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):
|
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):
|
class PreExec(Setting):
|
||||||
name = "pre_exec"
|
name = "pre_exec"
|
||||||
section = "Server Hooks"
|
section = "Server Hooks"
|
||||||
|
|||||||
@ -23,7 +23,7 @@ from gunicorn.six import MAXSIZE
|
|||||||
class Worker(object):
|
class Worker(object):
|
||||||
|
|
||||||
SIGNALS = [getattr(signal, "SIG%s" % x) \
|
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 = []
|
PIPE = []
|
||||||
|
|
||||||
@ -40,6 +40,7 @@ class Worker(object):
|
|||||||
self.timeout = timeout
|
self.timeout = timeout
|
||||||
self.cfg = cfg
|
self.cfg = cfg
|
||||||
self.booted = False
|
self.booted = False
|
||||||
|
self.aborted = False
|
||||||
|
|
||||||
self.nr = 0
|
self.nr = 0
|
||||||
self.max_requests = cfg.max_requests or MAXSIZE
|
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.SIGINT, self.handle_quit)
|
||||||
signal.signal(signal.SIGWINCH, self.handle_winch)
|
signal.signal(signal.SIGWINCH, self.handle_winch)
|
||||||
signal.signal(signal.SIGUSR1, self.handle_usr1)
|
signal.signal(signal.SIGUSR1, self.handle_usr1)
|
||||||
|
signal.signal(signal.SIGABRT, self.handle_abort)
|
||||||
|
|
||||||
# Don't let SIGQUIT and SIGUSR1 disturb active requests
|
# Don't let SIGQUIT and SIGUSR1 disturb active requests
|
||||||
# by interrupting system calls
|
# by interrupting system calls
|
||||||
if hasattr(signal, 'siginterrupt'): # python >= 2.6
|
if hasattr(signal, 'siginterrupt'): # python >= 2.6
|
||||||
@ -145,6 +148,11 @@ class Worker(object):
|
|||||||
self.alive = False
|
self.alive = False
|
||||||
sys.exit(0)
|
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):
|
def handle_error(self, req, client, addr, exc):
|
||||||
request_start = datetime.now()
|
request_start = datetime.now()
|
||||||
addr = addr or ('', -1) # unix socket case
|
addr = addr or ('', -1) # unix socket case
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user