diff --git a/examples/example_config.py b/examples/example_config.py index db8b1d9f..b3901a09 100644 --- a/examples/example_config.py +++ b/examples/example_config.py @@ -70,7 +70,7 @@ backlog = 2048 # workers = 1 -worker_class = 'egg:gunicorn#sync' +worker_class = 'sync' worker_connections = 1000 timeout = 30 keepalive = 2 @@ -200,3 +200,20 @@ def pre_exec(server): def when_ready(server): server.log.info("Server is ready. Spwawning workers") + +def worker_int(worker): + worker.log.info("worker received INT or TERM signal") + + ## get traceback info + import threading, sys, traceback + id2name = dict([(th.ident, th.name) for th in threading.enumerate()]) + code = [] + for threadId, stack in sys._current_frames().items(): + code.append("\n# Thread: %s(%d)" % (id2name.get(threadId,""), + threadId)) + for filename, lineno, name, line in traceback.extract_stack(stack): + code.append('File: "%s", line %d, in %s' % (filename, + lineno, name)) + if line: + code.append(" %s" % (line.strip())) + worker.log.debug("\n".join(code)) diff --git a/gunicorn/config.py b/gunicorn/config.py index e8f70722..1deca11b 100644 --- a/gunicorn/config.py +++ b/gunicorn/config.py @@ -1286,6 +1286,23 @@ class PostWorkerInit(Setting): Worker. """ +class WorkerInt(Setting): + name = "worker_int" + section = "Server Hooks" + validator = validate_callable(1) + type = six.callable + + def worker_int(worker): + pass + + default = staticmethod(worker_int) + desc = """\ + Called just after a worker exited on SIGINT or SIGTERM. + + The callable needs to accept one instance variable for the initialized + Worker. + """ + class PreExec(Setting): name = "pre_exec" diff --git a/gunicorn/workers/base.py b/gunicorn/workers/base.py index d69b083e..d41f3ef4 100644 --- a/gunicorn/workers/base.py +++ b/gunicorn/workers/base.py @@ -134,6 +134,8 @@ class Worker(object): def handle_exit(self, sig, frame): self.alive = False + # worker_int callback + self.cfg.worker_int(self) sys.exit(0) def handle_error(self, req, client, addr, exc):