mirror of
https://github.com/frappe/gunicorn.git
synced 2026-01-14 11:09:11 +08:00
parent
88804ae035
commit
719e61bf18
128
gunicorn/workers/_gaiohttp.py
Normal file
128
gunicorn/workers/_gaiohttp.py
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
# -*- coding: utf-8 -
|
||||||
|
#
|
||||||
|
# This file is part of gunicorn released under the MIT license.
|
||||||
|
# See the NOTICE for more information.
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import functools
|
||||||
|
import os
|
||||||
|
import gunicorn.workers.base as base
|
||||||
|
|
||||||
|
from aiohttp.wsgi import WSGIServerHttpProtocol
|
||||||
|
|
||||||
|
|
||||||
|
class AiohttpWorker(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()
|
||||||
|
|
||||||
|
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()
|
||||||
|
|
||||||
|
def wrap_protocol(self, proto):
|
||||||
|
proto.connection_made = _wrp(
|
||||||
|
proto, proto.connection_made, self.connections)
|
||||||
|
proto.connection_lost = _wrp(
|
||||||
|
proto, proto.connection_lost, self.connections, False)
|
||||||
|
return proto
|
||||||
|
|
||||||
|
def factory(self, wsgi, addr):
|
||||||
|
proto = WSGIServerHttpProtocol(
|
||||||
|
wsgi, readpayload=True,
|
||||||
|
loop=self.loop,
|
||||||
|
log=self.log,
|
||||||
|
debug=self.cfg.debug,
|
||||||
|
keep_alive=self.cfg.keepalive,
|
||||||
|
access_log=self.log.access_log,
|
||||||
|
access_log_format=self.cfg.access_log_format)
|
||||||
|
return self.wrap_protocol(proto)
|
||||||
|
|
||||||
|
def get_factory(self, sock, addr):
|
||||||
|
return functools.partial(self.factory, self.wsgi, addr)
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def close(self):
|
||||||
|
try:
|
||||||
|
if hasattr(self.wsgi, 'close'):
|
||||||
|
yield from self.wsgi.close()
|
||||||
|
except:
|
||||||
|
self.log.exception('Process shutdown exception')
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def _run(self):
|
||||||
|
for sock in self.sockets:
|
||||||
|
factory = self.get_factory(sock.sock, sock.cfg_addr)
|
||||||
|
self.servers.append(
|
||||||
|
(yield from self.loop.create_server(factory, sock=sock.sock)))
|
||||||
|
|
||||||
|
# If our parent changed then we shut down.
|
||||||
|
pid = os.getpid()
|
||||||
|
try:
|
||||||
|
while self.alive or self.connections:
|
||||||
|
self.notify()
|
||||||
|
|
||||||
|
if (self.alive and
|
||||||
|
pid == os.getpid() and self.ppid != os.getppid()):
|
||||||
|
self.log.info("Parent changed, shutting down: %s", self)
|
||||||
|
self.alive = False
|
||||||
|
|
||||||
|
# stop accepting requests
|
||||||
|
if not self.alive:
|
||||||
|
if self.servers:
|
||||||
|
self.log.info(
|
||||||
|
"Stopping server: %s, connections: %s",
|
||||||
|
pid, len(self.connections))
|
||||||
|
for server in self.servers:
|
||||||
|
server.close()
|
||||||
|
self.servers.clear()
|
||||||
|
|
||||||
|
# prepare connections for closing
|
||||||
|
for conn in self.connections.values():
|
||||||
|
if hasattr(conn, 'closing'):
|
||||||
|
conn.closing()
|
||||||
|
|
||||||
|
yield from asyncio.sleep(1.0, loop=self.loop)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if self.servers:
|
||||||
|
for server in self.servers:
|
||||||
|
server.close()
|
||||||
|
|
||||||
|
yield from self.close()
|
||||||
|
|
||||||
|
|
||||||
|
class _wrp:
|
||||||
|
|
||||||
|
def __init__(self, proto, meth, tracking, add=True):
|
||||||
|
self._proto = proto
|
||||||
|
self._id = id(proto)
|
||||||
|
self._meth = meth
|
||||||
|
self._tracking = tracking
|
||||||
|
self._add = add
|
||||||
|
|
||||||
|
def __call__(self, *args):
|
||||||
|
if self._add:
|
||||||
|
self._tracking[self._id] = self._proto
|
||||||
|
elif self._id in self._tracking:
|
||||||
|
del self._tracking[self._id]
|
||||||
|
|
||||||
|
conn = self._meth(*args)
|
||||||
|
return conn
|
||||||
@ -2,131 +2,16 @@
|
|||||||
#
|
#
|
||||||
# This file is part of gunicorn released under the MIT license.
|
# This file is part of gunicorn released under the MIT license.
|
||||||
# See the NOTICE for more information.
|
# See the NOTICE for more information.
|
||||||
__all__ = ['AiohttpWorker']
|
|
||||||
|
|
||||||
import asyncio
|
import sys
|
||||||
import functools
|
|
||||||
import os
|
|
||||||
import gunicorn.workers.base as base
|
|
||||||
|
|
||||||
try:
|
if sys.version_info >= (3, 3):
|
||||||
from aiohttp.wsgi import WSGIServerHttpProtocol
|
try:
|
||||||
except ImportError:
|
import aiohttp
|
||||||
raise RuntimeError("You need aiohttp installed to use this worker.")
|
except ImportError:
|
||||||
|
raise RuntimeError("You need aiohttp installed to use this worker.")
|
||||||
|
else:
|
||||||
class AiohttpWorker(base.Worker):
|
from gunicorn.workers._gaiohttp import AiohttpWorker
|
||||||
|
__all__ = ['AiohttpWorker']
|
||||||
def __init__(self, *args, **kw): # pragma: no cover
|
else:
|
||||||
super().__init__(*args, **kw)
|
raise RuntimeError("You need Python >= 3.3 to use the asyncio worker")
|
||||||
|
|
||||||
self.servers = []
|
|
||||||
self.connections = {}
|
|
||||||
|
|
||||||
def init_process(self):
|
|
||||||
# create new event_loop after fork
|
|
||||||
asyncio.get_event_loop().close()
|
|
||||||
|
|
||||||
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()
|
|
||||||
|
|
||||||
def wrap_protocol(self, proto):
|
|
||||||
proto.connection_made = _wrp(
|
|
||||||
proto, proto.connection_made, self.connections)
|
|
||||||
proto.connection_lost = _wrp(
|
|
||||||
proto, proto.connection_lost, self.connections, False)
|
|
||||||
return proto
|
|
||||||
|
|
||||||
def factory(self, wsgi, addr):
|
|
||||||
proto = WSGIServerHttpProtocol(
|
|
||||||
wsgi, readpayload=True,
|
|
||||||
loop=self.loop,
|
|
||||||
log=self.log,
|
|
||||||
debug=self.cfg.debug,
|
|
||||||
keep_alive=self.cfg.keepalive,
|
|
||||||
access_log=self.log.access_log,
|
|
||||||
access_log_format=self.cfg.access_log_format)
|
|
||||||
return self.wrap_protocol(proto)
|
|
||||||
|
|
||||||
def get_factory(self, sock, addr):
|
|
||||||
return functools.partial(self.factory, self.wsgi, addr)
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def close(self):
|
|
||||||
try:
|
|
||||||
if hasattr(self.wsgi, 'close'):
|
|
||||||
yield from self.wsgi.close()
|
|
||||||
except:
|
|
||||||
self.log.exception('Process shutdown exception')
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def _run(self):
|
|
||||||
for sock in self.sockets:
|
|
||||||
factory = self.get_factory(sock.sock, sock.cfg_addr)
|
|
||||||
self.servers.append(
|
|
||||||
(yield from self.loop.create_server(factory, sock=sock.sock)))
|
|
||||||
|
|
||||||
# If our parent changed then we shut down.
|
|
||||||
pid = os.getpid()
|
|
||||||
try:
|
|
||||||
while self.alive or self.connections:
|
|
||||||
self.notify()
|
|
||||||
|
|
||||||
if (self.alive and
|
|
||||||
pid == os.getpid() and self.ppid != os.getppid()):
|
|
||||||
self.log.info("Parent changed, shutting down: %s", self)
|
|
||||||
self.alive = False
|
|
||||||
|
|
||||||
# stop accepting requests
|
|
||||||
if not self.alive:
|
|
||||||
if self.servers:
|
|
||||||
self.log.info(
|
|
||||||
"Stopping server: %s, connections: %s",
|
|
||||||
pid, len(self.connections))
|
|
||||||
for server in self.servers:
|
|
||||||
server.close()
|
|
||||||
self.servers.clear()
|
|
||||||
|
|
||||||
# prepare connections for closing
|
|
||||||
for conn in self.connections.values():
|
|
||||||
if hasattr(conn, 'closing'):
|
|
||||||
conn.closing()
|
|
||||||
|
|
||||||
yield from asyncio.sleep(1.0, loop=self.loop)
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if self.servers:
|
|
||||||
for server in self.servers:
|
|
||||||
server.close()
|
|
||||||
|
|
||||||
yield from self.close()
|
|
||||||
|
|
||||||
|
|
||||||
class _wrp:
|
|
||||||
|
|
||||||
def __init__(self, proto, meth, tracking, add=True):
|
|
||||||
self._proto = proto
|
|
||||||
self._id = id(proto)
|
|
||||||
self._meth = meth
|
|
||||||
self._tracking = tracking
|
|
||||||
self._add = add
|
|
||||||
|
|
||||||
def __call__(self, *args):
|
|
||||||
if self._add:
|
|
||||||
self._tracking[self._id] = self._proto
|
|
||||||
elif self._id in self._tracking:
|
|
||||||
del self._tracking[self._id]
|
|
||||||
|
|
||||||
conn = self._meth(*args)
|
|
||||||
return conn
|
|
||||||
|
|||||||
22
setup.py
22
setup.py
@ -5,17 +5,14 @@
|
|||||||
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from setuptools import setup
|
|
||||||
from setuptools.command.test import test as TestCommand
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
from setuptools import setup, find_packages
|
||||||
|
from setuptools.command.test import test as TestCommand
|
||||||
|
|
||||||
from gunicorn import __version__
|
from gunicorn import __version__
|
||||||
|
|
||||||
|
|
||||||
ASYNCIO_COMPAT = sys.version_info >= (3, 3)
|
|
||||||
|
|
||||||
|
|
||||||
CLASSIFIERS = [
|
CLASSIFIERS = [
|
||||||
'Development Status :: 4 - Beta',
|
'Development Status :: 4 - Beta',
|
||||||
'Environment :: Other Environment',
|
'Environment :: Other Environment',
|
||||||
@ -71,17 +68,6 @@ class PyTest(TestCommand):
|
|||||||
|
|
||||||
REQUIREMENTS = []
|
REQUIREMENTS = []
|
||||||
|
|
||||||
py_modules = []
|
|
||||||
|
|
||||||
for root, folders, files in os.walk('gunicorn'):
|
|
||||||
for f in files:
|
|
||||||
if f.endswith('.py') and (ASYNCIO_COMPAT or f != 'gaiohttp.py'):
|
|
||||||
full = os.path.join(root, f[:-3])
|
|
||||||
parts = full.split(os.path.sep)
|
|
||||||
modname = '.'.join(parts)
|
|
||||||
py_modules.append(modname)
|
|
||||||
|
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name = 'gunicorn',
|
name = 'gunicorn',
|
||||||
version = __version__,
|
version = __version__,
|
||||||
@ -95,7 +81,7 @@ setup(
|
|||||||
|
|
||||||
classifiers = CLASSIFIERS,
|
classifiers = CLASSIFIERS,
|
||||||
zip_safe = False,
|
zip_safe = False,
|
||||||
py_modules = py_modules,
|
packages = find_packages(exclude=['examples', 'tests']),
|
||||||
include_package_data = True,
|
include_package_data = True,
|
||||||
|
|
||||||
tests_require = tests_require,
|
tests_require = tests_require,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user