From 19ee1dfecca09d23cc450df86c42e26ffd1548fb Mon Sep 17 00:00:00 2001 From: messense Date: Sun, 12 Mar 2017 16:19:34 +0800 Subject: [PATCH] Gunicorn worker --- sanic/app.py | 13 ++++++---- sanic/worker.py | 63 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 4 deletions(-) create mode 100644 sanic/worker.py diff --git a/sanic/app.py b/sanic/app.py index 2fd52fae..e101caf5 100644 --- a/sanic/app.py +++ b/sanic/app.py @@ -578,6 +578,10 @@ class Sanic: """This kills the Sanic""" get_event_loop().stop() + def __call__(self): + """gunicorn compatibility""" + return self + async def create_server(self, host="127.0.0.1", port=8000, debug=False, before_start=None, after_start=None, before_stop=None, after_stop=None, ssl=None, @@ -686,9 +690,10 @@ class Sanic: server_settings['run_async'] = True # Serve - proto = "http" - if ssl is not None: - proto = "https" - log.info('Goin\' Fast @ {}://{}:{}'.format(proto, host, port)) + if host and port: + proto = "http" + if ssl is not None: + proto = "https" + log.info('Goin\' Fast @ {}://{}:{}'.format(proto, host, port)) return server_settings diff --git a/sanic/worker.py b/sanic/worker.py new file mode 100644 index 00000000..e4906faf --- /dev/null +++ b/sanic/worker.py @@ -0,0 +1,63 @@ +import asyncio +import os + +import uvloop +import gunicorn.workers.base as base + + +class GunicornWorker(base.Worker): + + def __init__(self, *args, **kw): # pragma: no cover + super().__init__(*args, **kw) + self.servers = [] + self.connections = {} + + def init_process(self): + # create new event_loop after fork + asyncio.get_event_loop().close() + + asyncio.set_event_loop_policy(uvloop.EventLoopPolicy()) + self.loop = asyncio.new_event_loop() + asyncio.set_event_loop(self.loop) + + super().init_process() + + def run(self): + self._runner = asyncio.async(self._run(), loop=self.loop) + + try: + self.loop.run_until_complete(self._runner) + finally: + self.loop.close() + + async def close(self): + try: + if hasattr(self.wsgi, 'close'): + await self.wsgi.close() + except: + self.log.exception('Process shutdown exception') + + async def _run(self): + for sock in self.sockets: + self.servers.append(await self.app.callable.create_server( + sock=sock, host=None, port=None, loop=self.loop)) + + # If our parent changed then we shut down. + pid = os.getpid() + try: + while self.alive: + self.notify() + + if pid == os.getpid() and self.ppid != os.getppid(): + self.alive = False + self.log.info("Parent changed, shutting down: %s", self) + else: + await asyncio.sleep(1.0, loop=self.loop) + except (Exception, BaseException, GeneratorExit, KeyboardInterrupt): + pass + + if self.servers: + for server in self.servers: + server.close() + + await self.close()