mirror of
https://github.com/frappe/gunicorn.git
synced 2026-01-14 11:09:11 +08:00
Merge remote-tracking branch 'origin/master' into syslog_socktype
This commit is contained in:
commit
5b0ae52c8a
@ -11,21 +11,34 @@ ignore-paths:
|
|||||||
- scripts
|
- scripts
|
||||||
- tests/requests/valid
|
- tests/requests/valid
|
||||||
- tests/requests/invalid
|
- tests/requests/invalid
|
||||||
|
- tests/treq.py # We are going to replace this with pytest.
|
||||||
|
- tests/t.py # Same as above.
|
||||||
|
- tests/test_selectors.py # This basically port of upstream selectors tests.
|
||||||
|
- tests/test_gaiohttp.py # TODO: We are going to remove this worker.
|
||||||
|
|
||||||
pep8:
|
pep8:
|
||||||
disable:
|
run: false
|
||||||
- E126
|
|
||||||
- E128
|
|
||||||
- E129
|
|
||||||
- E302
|
|
||||||
- E501
|
|
||||||
|
|
||||||
pyflakes:
|
pyflakes:
|
||||||
|
run: false
|
||||||
|
|
||||||
|
pylint:
|
||||||
disable:
|
disable:
|
||||||
# Redefinition of unused $X from line $LINE
|
- bare-except
|
||||||
- F811
|
- misplaced-comparison-constant
|
||||||
# Access to a protected member $X of a client class
|
- protected-access
|
||||||
- W0212
|
- import-error
|
||||||
|
- too-many-branches
|
||||||
|
- too-many-arguments
|
||||||
|
- too-many-nested-blocks
|
||||||
|
- eval-used
|
||||||
|
- no-else-return
|
||||||
|
- wrong-import-position
|
||||||
|
- unused-argument
|
||||||
|
- import-self
|
||||||
|
- duplicate-bases
|
||||||
|
- no-staticmethod-decorator
|
||||||
|
- not-callable
|
||||||
|
|
||||||
mccabe:
|
mccabe:
|
||||||
run: false
|
run: false
|
||||||
|
|||||||
@ -16,7 +16,7 @@ matrix:
|
|||||||
env: TOXENV=py36-dev
|
env: TOXENV=py36-dev
|
||||||
- python: nightly
|
- python: nightly
|
||||||
env: TOXENV=py37
|
env: TOXENV=py37
|
||||||
- python: 3.5
|
- python: 3.6
|
||||||
env: TOXENV=lint
|
env: TOXENV=lint
|
||||||
allow_failures:
|
allow_failures:
|
||||||
- env: TOXENV=py36-dev
|
- env: TOXENV=py36-dev
|
||||||
|
|||||||
@ -320,6 +320,37 @@ because it consumes less system resources.
|
|||||||
In order to use the inotify reloader, you must have the ``inotify``
|
In order to use the inotify reloader, you must have the ``inotify``
|
||||||
package installed.
|
package installed.
|
||||||
|
|
||||||
|
.. _reload-engine:
|
||||||
|
|
||||||
|
reload_engine
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
* ``--reload-engine STRING``
|
||||||
|
* ``auto``
|
||||||
|
|
||||||
|
The implementation that should be used to power :ref:`reload`.
|
||||||
|
|
||||||
|
Valid engines are:
|
||||||
|
|
||||||
|
* 'auto'
|
||||||
|
* 'poll'
|
||||||
|
* 'inotify' (requires inotify)
|
||||||
|
|
||||||
|
.. versionadded:: 19.7
|
||||||
|
|
||||||
|
.. _reload-extra-files:
|
||||||
|
|
||||||
|
reload_extra_files
|
||||||
|
~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
* ``--reload-extra-file FILES``
|
||||||
|
* ``[]``
|
||||||
|
|
||||||
|
Extends :ref:`reload` option to also watch and reload on additional files
|
||||||
|
(e.g., templates, configurations, specifications, etc.).
|
||||||
|
|
||||||
|
.. versionadded:: 19.8
|
||||||
|
|
||||||
.. _spew:
|
.. _spew:
|
||||||
|
|
||||||
spew
|
spew
|
||||||
|
|||||||
@ -262,3 +262,37 @@ if PY26:
|
|||||||
|
|
||||||
else:
|
else:
|
||||||
from gunicorn.six.moves.urllib.parse import urlsplit
|
from gunicorn.six.moves.urllib.parse import urlsplit
|
||||||
|
|
||||||
|
|
||||||
|
import inspect
|
||||||
|
|
||||||
|
if hasattr(inspect, 'signature'):
|
||||||
|
positionals = (
|
||||||
|
inspect.Parameter.POSITIONAL_ONLY,
|
||||||
|
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_arity(f):
|
||||||
|
sig = inspect.signature(f)
|
||||||
|
arity = 0
|
||||||
|
|
||||||
|
for param in sig.parameters.values():
|
||||||
|
if param.kind in positionals:
|
||||||
|
arity += 1
|
||||||
|
|
||||||
|
return arity
|
||||||
|
else:
|
||||||
|
def get_arity(f):
|
||||||
|
return len(inspect.getargspec(f)[0])
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
import html
|
||||||
|
|
||||||
|
def html_escape(s):
|
||||||
|
return html.escape(s)
|
||||||
|
except ImportError:
|
||||||
|
import cgi
|
||||||
|
|
||||||
|
def html_escape(s):
|
||||||
|
return cgi.escape(s, quote=True)
|
||||||
|
|||||||
@ -173,8 +173,8 @@ class Arbiter(object):
|
|||||||
are queued. Child signals only wake up the master.
|
are queued. Child signals only wake up the master.
|
||||||
"""
|
"""
|
||||||
# close old PIPE
|
# close old PIPE
|
||||||
if self.PIPE:
|
for p in self.PIPE:
|
||||||
[os.close(p) for p in self.PIPE]
|
os.close(p)
|
||||||
|
|
||||||
# initialize the pipe
|
# initialize the pipe
|
||||||
self.PIPE = pair = os.pipe()
|
self.PIPE = pair = os.pipe()
|
||||||
@ -185,7 +185,8 @@ class Arbiter(object):
|
|||||||
self.log.close_on_exec()
|
self.log.close_on_exec()
|
||||||
|
|
||||||
# initialize all signals
|
# initialize all signals
|
||||||
[signal.signal(s, self.signal) for s in self.SIGNALS]
|
for s in self.SIGNALS:
|
||||||
|
signal.signal(s, self.signal)
|
||||||
signal.signal(signal.SIGCHLD, self.handle_chld)
|
signal.signal(signal.SIGCHLD, self.handle_chld)
|
||||||
|
|
||||||
def signal(self, sig, frame):
|
def signal(self, sig, frame):
|
||||||
@ -204,7 +205,7 @@ class Arbiter(object):
|
|||||||
while True:
|
while True:
|
||||||
self.maybe_promote_master()
|
self.maybe_promote_master()
|
||||||
|
|
||||||
sig = self.SIG_QUEUE.pop(0) if len(self.SIG_QUEUE) else None
|
sig = self.SIG_QUEUE.pop(0) if self.SIG_QUEUE else None
|
||||||
if sig is None:
|
if sig is None:
|
||||||
self.sleep()
|
self.sleep()
|
||||||
self.murder_workers()
|
self.murder_workers()
|
||||||
@ -361,11 +362,10 @@ class Arbiter(object):
|
|||||||
return
|
return
|
||||||
while os.read(self.PIPE[0], 1):
|
while os.read(self.PIPE[0], 1):
|
||||||
pass
|
pass
|
||||||
except select.error as e:
|
except (select.error, OSError) as e:
|
||||||
if e.args[0] not in [errno.EAGAIN, errno.EINTR]:
|
# TODO: select.error is a subclass of OSError since Python 3.3.
|
||||||
raise
|
error_number = getattr(e, 'errno', e.args[0])
|
||||||
except OSError as e:
|
if error_number not in [errno.EAGAIN, errno.EINTR]:
|
||||||
if e.errno not in [errno.EAGAIN, errno.EINTR]:
|
|
||||||
raise
|
raise
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
sys.exit()
|
sys.exit()
|
||||||
@ -454,7 +454,8 @@ class Arbiter(object):
|
|||||||
# do we need to change listener ?
|
# do we need to change listener ?
|
||||||
if old_address != self.cfg.address:
|
if old_address != self.cfg.address:
|
||||||
# close all listeners
|
# close all listeners
|
||||||
[l.close() for l in self.LISTENERS]
|
for l in self.LISTENERS:
|
||||||
|
l.close()
|
||||||
# init new listeners
|
# init new listeners
|
||||||
self.LISTENERS = sock.create_sockets(self.cfg, self.log)
|
self.LISTENERS = sock.create_sockets(self.cfg, self.log)
|
||||||
listeners_str = ",".join([str(l) for l in self.LISTENERS])
|
listeners_str = ",".join([str(l) for l in self.LISTENERS])
|
||||||
@ -476,7 +477,7 @@ class Arbiter(object):
|
|||||||
util._setproctitle("master [%s]" % self.proc_name)
|
util._setproctitle("master [%s]" % self.proc_name)
|
||||||
|
|
||||||
# spawn new workers
|
# spawn new workers
|
||||||
for i in range(self.cfg.workers):
|
for _ in range(self.cfg.workers):
|
||||||
self.spawn_worker()
|
self.spawn_worker()
|
||||||
|
|
||||||
# manage workers
|
# manage workers
|
||||||
@ -586,7 +587,7 @@ class Arbiter(object):
|
|||||||
sys.stderr.flush()
|
sys.stderr.flush()
|
||||||
sys.exit(self.APP_LOAD_ERROR)
|
sys.exit(self.APP_LOAD_ERROR)
|
||||||
except:
|
except:
|
||||||
self.log.exception("Exception in worker process"),
|
self.log.exception("Exception in worker process")
|
||||||
if not worker.booted:
|
if not worker.booted:
|
||||||
sys.exit(self.WORKER_BOOT_ERROR)
|
sys.exit(self.WORKER_BOOT_ERROR)
|
||||||
sys.exit(-1)
|
sys.exit(-1)
|
||||||
@ -607,7 +608,7 @@ class Arbiter(object):
|
|||||||
of the master process.
|
of the master process.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
for i in range(self.num_workers - len(self.WORKERS.keys())):
|
for _ in range(self.num_workers - len(self.WORKERS.keys())):
|
||||||
self.spawn_worker()
|
self.spawn_worker()
|
||||||
time.sleep(0.1 * random.random())
|
time.sleep(0.1 * random.random())
|
||||||
|
|
||||||
|
|||||||
@ -426,7 +426,7 @@ def validate_callable(arity):
|
|||||||
"" % (obj_name, mod_name))
|
"" % (obj_name, mod_name))
|
||||||
if not six.callable(val):
|
if not six.callable(val):
|
||||||
raise TypeError("Value is not six.callable: %s" % val)
|
raise TypeError("Value is not six.callable: %s" % val)
|
||||||
if arity != -1 and arity != len(inspect.getargspec(val)[0]):
|
if arity != -1 and arity != _compat.get_arity(val):
|
||||||
raise TypeError("Value must have an arity of: %s" % arity)
|
raise TypeError("Value must have an arity of: %s" % arity)
|
||||||
return val
|
return val
|
||||||
return _validate_callable
|
return _validate_callable
|
||||||
@ -464,7 +464,7 @@ def validate_group(val):
|
|||||||
def validate_post_request(val):
|
def validate_post_request(val):
|
||||||
val = validate_callable(-1)(val)
|
val = validate_callable(-1)(val)
|
||||||
|
|
||||||
largs = len(inspect.getargspec(val)[0])
|
largs = _compat.get_arity(val)
|
||||||
if largs == 4:
|
if largs == 4:
|
||||||
return val
|
return val
|
||||||
elif largs == 3:
|
elif largs == 3:
|
||||||
@ -652,6 +652,11 @@ class WorkerThreads(Setting):
|
|||||||
If it is not defined, the default is ``1``.
|
If it is not defined, the default is ``1``.
|
||||||
|
|
||||||
This setting only affects the Gthread worker type.
|
This setting only affects the Gthread worker type.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
If you try to use the ``sync`` worker type and set the ``threads``
|
||||||
|
setting to more than 1, the ``gthread`` worker type will be used
|
||||||
|
instead.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@ -878,8 +883,10 @@ class ReloadExtraFiles(Setting):
|
|||||||
validator = validate_list_of_existing_files
|
validator = validate_list_of_existing_files
|
||||||
default = []
|
default = []
|
||||||
desc = """\
|
desc = """\
|
||||||
Extends --reload option to also watch and reload on additional files
|
Extends :ref:`reload` option to also watch and reload on additional files
|
||||||
(e.g., templates, configurations, specifications, etc.).
|
(e.g., templates, configurations, specifications, etc.).
|
||||||
|
|
||||||
|
.. versionadded:: 19.8
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -326,7 +326,7 @@ class Logger(object):
|
|||||||
request_time))
|
request_time))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.access_log.info(self.cfg.access_log_format % safe_atoms)
|
self.access_log.info(self.cfg.access_log_format, safe_atoms)
|
||||||
except:
|
except:
|
||||||
self.error(traceback.format_exc())
|
self.error(traceback.format_exc())
|
||||||
|
|
||||||
|
|||||||
@ -210,7 +210,7 @@ class Body(object):
|
|||||||
|
|
||||||
while size > self.buf.tell():
|
while size > self.buf.tell():
|
||||||
data = self.reader.read(1024)
|
data = self.reader.read(1024)
|
||||||
if not len(data):
|
if not data:
|
||||||
break
|
break
|
||||||
self.buf.write(data)
|
self.buf.write(data)
|
||||||
|
|
||||||
@ -248,7 +248,7 @@ class Body(object):
|
|||||||
def readlines(self, size=None):
|
def readlines(self, size=None):
|
||||||
ret = []
|
ret = []
|
||||||
data = self.read()
|
data = self.read()
|
||||||
while len(data):
|
while data:
|
||||||
pos = data.find(b"\n")
|
pos = data.find(b"\n")
|
||||||
if pos < 0:
|
if pos < 0:
|
||||||
ret.append(data)
|
ret.append(data)
|
||||||
|
|||||||
@ -53,7 +53,7 @@ class Message(object):
|
|||||||
self.unreader.unread(unused)
|
self.unreader.unread(unused)
|
||||||
self.set_body_reader()
|
self.set_body_reader()
|
||||||
|
|
||||||
def parse(self):
|
def parse(self, unreader):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
def parse_headers(self, data):
|
def parse_headers(self, data):
|
||||||
@ -64,7 +64,7 @@ class Message(object):
|
|||||||
|
|
||||||
# Parse headers into key/value pairs paying attention
|
# Parse headers into key/value pairs paying attention
|
||||||
# to continuation lines.
|
# to continuation lines.
|
||||||
while len(lines):
|
while lines:
|
||||||
if len(headers) >= self.limit_request_fields:
|
if len(headers) >= self.limit_request_fields:
|
||||||
raise LimitRequestHeaders("limit request headers fields")
|
raise LimitRequestHeaders("limit request headers fields")
|
||||||
|
|
||||||
@ -81,7 +81,7 @@ class Message(object):
|
|||||||
name, value = name.strip(), [value.lstrip()]
|
name, value = name.strip(), [value.lstrip()]
|
||||||
|
|
||||||
# Consume value continuation lines
|
# Consume value continuation lines
|
||||||
while len(lines) and lines[0].startswith((" ", "\t")):
|
while lines and lines[0].startswith((" ", "\t")):
|
||||||
curr = lines.pop(0)
|
curr = lines.pop(0)
|
||||||
header_length += len(curr)
|
header_length += len(curr)
|
||||||
if header_length > self.limit_request_field_size > 0:
|
if header_length > self.limit_request_field_size > 0:
|
||||||
|
|||||||
@ -40,7 +40,7 @@ class Unreader(object):
|
|||||||
|
|
||||||
while self.buf.tell() < size:
|
while self.buf.tell() < size:
|
||||||
chunk = self.chunk()
|
chunk = self.chunk()
|
||||||
if not len(chunk):
|
if not chunk:
|
||||||
ret = self.buf.getvalue()
|
ret = self.buf.getvalue()
|
||||||
self.buf = six.BytesIO()
|
self.buf = six.BytesIO()
|
||||||
return ret
|
return ret
|
||||||
|
|||||||
@ -183,7 +183,7 @@ def create(req, sock, client, server, cfg):
|
|||||||
server = host.split(':')
|
server = host.split(':')
|
||||||
if len(server) == 1:
|
if len(server) == 1:
|
||||||
if url_scheme == "http":
|
if url_scheme == "http":
|
||||||
server.append(80),
|
server.append(80)
|
||||||
elif url_scheme == "https":
|
elif url_scheme == "https":
|
||||||
server.append(443)
|
server.append(443)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@ -80,7 +80,7 @@ class Statsd(Logger):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
# Log to parent logger only if there is something to say
|
# Log to parent logger only if there is something to say
|
||||||
if msg is not None and len(msg) > 0:
|
if msg:
|
||||||
Logger.log(self, lvl, msg, *args, **kwargs)
|
Logger.log(self, lvl, msg, *args, **kwargs)
|
||||||
except Exception:
|
except Exception:
|
||||||
Logger.warning(self, "Failed to log to statsd", exc_info=True)
|
Logger.warning(self, "Failed to log to statsd", exc_info=True)
|
||||||
@ -108,7 +108,7 @@ class Statsd(Logger):
|
|||||||
self._sock_send("{0}{1}:{2}|c|@{3}".format(self.prefix, name, value, sampling_rate))
|
self._sock_send("{0}{1}:{2}|c|@{3}".format(self.prefix, name, value, sampling_rate))
|
||||||
|
|
||||||
def decrement(self, name, value, sampling_rate=1.0):
|
def decrement(self, name, value, sampling_rate=1.0):
|
||||||
self._sock_send("{0){1}:-{2}|c|@{3}".format(self.prefix, name, value, sampling_rate))
|
self._sock_send("{0}{1}:-{2}|c|@{3}".format(self.prefix, name, value, sampling_rate))
|
||||||
|
|
||||||
def histogram(self, name, value):
|
def histogram(self, name, value):
|
||||||
self._sock_send("{0}{1}:{2}|ms".format(self.prefix, name, value))
|
self._sock_send("{0}{1}:{2}|ms".format(self.prefix, name, value))
|
||||||
|
|||||||
@ -53,19 +53,16 @@ class Reloader(threading.Thread):
|
|||||||
self._callback(filename)
|
self._callback(filename)
|
||||||
time.sleep(self._interval)
|
time.sleep(self._interval)
|
||||||
|
|
||||||
try:
|
has_inotify = False
|
||||||
from inotify.adapters import Inotify
|
if sys.platform.startswith('linux'):
|
||||||
import inotify.constants
|
try:
|
||||||
has_inotify = True
|
from inotify.adapters import Inotify
|
||||||
except ImportError:
|
import inotify.constants
|
||||||
has_inotify = False
|
has_inotify = True
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class InotifyReloader():
|
|
||||||
def __init__(self, callback=None):
|
|
||||||
raise ImportError('You must have the inotify module installed to use '
|
|
||||||
'the inotify reloader')
|
|
||||||
|
|
||||||
if has_inotify:
|
if has_inotify:
|
||||||
|
|
||||||
class InotifyReloader(threading.Thread):
|
class InotifyReloader(threading.Thread):
|
||||||
@ -116,6 +113,13 @@ if has_inotify:
|
|||||||
|
|
||||||
self._callback(filename)
|
self._callback(filename)
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
class InotifyReloader(object):
|
||||||
|
def __init__(self, callback=None):
|
||||||
|
raise ImportError('You must have the inotify module installed to '
|
||||||
|
'use the inotify reloader')
|
||||||
|
|
||||||
|
|
||||||
preferred_reloader = InotifyReloader if has_inotify else Reloader
|
preferred_reloader = InotifyReloader if has_inotify else Reloader
|
||||||
|
|
||||||
|
|||||||
@ -31,7 +31,7 @@ class BaseSocket(object):
|
|||||||
|
|
||||||
self.sock = self.set_options(sock, bound=bound)
|
self.sock = self.set_options(sock, bound=bound)
|
||||||
|
|
||||||
def __str__(self, name):
|
def __str__(self):
|
||||||
return "<socket %d>" % self.sock.fileno()
|
return "<socket %d>" % self.sock.fileno()
|
||||||
|
|
||||||
def __getattr__(self, name):
|
def __getattr__(self, name):
|
||||||
@ -94,7 +94,7 @@ class TCP6Socket(TCPSocket):
|
|||||||
FAMILY = socket.AF_INET6
|
FAMILY = socket.AF_INET6
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
(host, port, fl, sc) = self.sock.getsockname()
|
(host, port, _, _) = self.sock.getsockname()
|
||||||
return "http://[%s]:%d" % (host, port)
|
return "http://[%s]:%d" % (host, port)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -20,9 +20,9 @@ import traceback
|
|||||||
import inspect
|
import inspect
|
||||||
import errno
|
import errno
|
||||||
import warnings
|
import warnings
|
||||||
import cgi
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from gunicorn import _compat
|
||||||
from gunicorn.errors import AppImportError
|
from gunicorn.errors import AppImportError
|
||||||
from gunicorn.six import text_type
|
from gunicorn.six import text_type
|
||||||
from gunicorn.workers import SUPPORTED_WORKERS
|
from gunicorn.workers import SUPPORTED_WORKERS
|
||||||
@ -61,7 +61,7 @@ except ImportError:
|
|||||||
if not hasattr(package, 'rindex'):
|
if not hasattr(package, 'rindex'):
|
||||||
raise ValueError("'package' not set to a string")
|
raise ValueError("'package' not set to a string")
|
||||||
dot = len(package)
|
dot = len(package)
|
||||||
for x in range(level, 1, -1):
|
for _ in range(level, 1, -1):
|
||||||
try:
|
try:
|
||||||
dot = package.rindex('.', 0, dot)
|
dot = package.rindex('.', 0, dot)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
@ -329,7 +329,7 @@ def write_error(sock, status_int, reason, mesg):
|
|||||||
%(mesg)s
|
%(mesg)s
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
""") % {"reason": reason, "mesg": cgi.escape(mesg)}
|
""") % {"reason": reason, "mesg": _compat.html_escape(mesg)}
|
||||||
|
|
||||||
http = textwrap.dedent("""\
|
http = textwrap.dedent("""\
|
||||||
HTTP/1.1 %s %s\r
|
HTTP/1.1 %s %s\r
|
||||||
|
|||||||
@ -101,7 +101,8 @@ class Worker(object):
|
|||||||
util.close_on_exec(p)
|
util.close_on_exec(p)
|
||||||
|
|
||||||
# Prevent fd inheritance
|
# Prevent fd inheritance
|
||||||
[util.close_on_exec(s) for s in self.sockets]
|
for s in self.sockets:
|
||||||
|
util.close_on_exec(s)
|
||||||
util.close_on_exec(self.tmp.fileno())
|
util.close_on_exec(self.tmp.fileno())
|
||||||
|
|
||||||
self.wait_fds = self.sockets + [self.PIPE[0]]
|
self.wait_fds = self.sockets + [self.PIPE[0]]
|
||||||
@ -145,7 +146,7 @@ class Worker(object):
|
|||||||
# per https://docs.python.org/2/library/sys.html#sys.exc_info warning,
|
# per https://docs.python.org/2/library/sys.html#sys.exc_info warning,
|
||||||
# delete the traceback after use.
|
# delete the traceback after use.
|
||||||
try:
|
try:
|
||||||
exc_type, exc_val, exc_tb = sys.exc_info()
|
_, exc_val, exc_tb = sys.exc_info()
|
||||||
self.reloader.add_extra_file(exc_val.filename)
|
self.reloader.add_extra_file(exc_val.filename)
|
||||||
|
|
||||||
tb_string = six.StringIO()
|
tb_string = six.StringIO()
|
||||||
@ -156,7 +157,8 @@ class Worker(object):
|
|||||||
|
|
||||||
def init_signals(self):
|
def init_signals(self):
|
||||||
# reset signaling
|
# reset signaling
|
||||||
[signal.signal(s, signal.SIG_DFL) for s in self.SIGNALS]
|
for s in self.SIGNALS:
|
||||||
|
signal.signal(s, signal.SIG_DFL)
|
||||||
# init new signaling
|
# init new signaling
|
||||||
signal.signal(signal.SIGQUIT, self.handle_quit)
|
signal.signal(signal.SIGQUIT, self.handle_quit)
|
||||||
signal.signal(signal.SIGTERM, self.handle_exit)
|
signal.signal(signal.SIGTERM, self.handle_exit)
|
||||||
|
|||||||
@ -134,9 +134,12 @@ class EventletWorker(AsyncWorker):
|
|||||||
self.notify()
|
self.notify()
|
||||||
try:
|
try:
|
||||||
with eventlet.Timeout(self.cfg.graceful_timeout) as t:
|
with eventlet.Timeout(self.cfg.graceful_timeout) as t:
|
||||||
[a.kill(eventlet.StopServe()) for a in acceptors]
|
for a in acceptors:
|
||||||
[a.wait() for a in acceptors]
|
a.kill(eventlet.StopServe())
|
||||||
|
for a in acceptors:
|
||||||
|
a.wait()
|
||||||
except eventlet.Timeout as te:
|
except eventlet.Timeout as te:
|
||||||
if te != t:
|
if te != t:
|
||||||
raise
|
raise
|
||||||
[a.kill() for a in acceptors]
|
for a in acceptors:
|
||||||
|
a.kill()
|
||||||
|
|||||||
@ -143,13 +143,15 @@ class GeventWorker(AsyncWorker):
|
|||||||
|
|
||||||
# Force kill all active the handlers
|
# Force kill all active the handlers
|
||||||
self.log.warning("Worker graceful timeout (pid:%s)" % self.pid)
|
self.log.warning("Worker graceful timeout (pid:%s)" % self.pid)
|
||||||
[server.stop(timeout=1) for server in servers]
|
for server in servers:
|
||||||
|
server.stop(timeout=1)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def handle_request(self, *args):
|
def handle_request(self, listener_name, req, sock, addr):
|
||||||
try:
|
try:
|
||||||
super(GeventWorker, self).handle_request(*args)
|
super(GeventWorker, self).handle_request(listener_name, req, sock,
|
||||||
|
addr)
|
||||||
except gevent.GreenletExit:
|
except gevent.GreenletExit:
|
||||||
pass
|
pass
|
||||||
except SystemExit:
|
except SystemExit:
|
||||||
|
|||||||
@ -211,7 +211,7 @@ class ThreadWorker(base.Worker):
|
|||||||
if self.nr_conns < self.worker_connections:
|
if self.nr_conns < self.worker_connections:
|
||||||
# wait for an event
|
# wait for an event
|
||||||
events = self.poller.select(1.0)
|
events = self.poller.select(1.0)
|
||||||
for key, mask in events:
|
for key, _ in events:
|
||||||
callback = key.data
|
callback = key.data
|
||||||
callback(key.fileobj)
|
callback(key.fileobj)
|
||||||
|
|
||||||
|
|||||||
@ -34,7 +34,7 @@ def requires_mac_ver(*min_version):
|
|||||||
return decorator
|
return decorator
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from types import SimpleNamespace
|
from types import SimpleNamespace # noqa
|
||||||
except ImportError:
|
except ImportError:
|
||||||
class SimpleNamespace(object):
|
class SimpleNamespace(object):
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
|
|||||||
@ -29,7 +29,7 @@ class request(object):
|
|||||||
def __call__(self, func):
|
def __call__(self, func):
|
||||||
def run():
|
def run():
|
||||||
src = data_source(self.fname)
|
src = data_source(self.fname)
|
||||||
func(src, RequestParser(src))
|
func(src, RequestParser(src, None))
|
||||||
run.func_name = func.func_name
|
run.func_name = func.func_name
|
||||||
return run
|
return run
|
||||||
|
|
||||||
|
|||||||
@ -35,6 +35,7 @@ def test_validate_no_file(_open):
|
|||||||
def test_validate_file_pid_exists(kill, _open):
|
def test_validate_file_pid_exists(kill, _open):
|
||||||
pidfile = gunicorn.pidfile.Pidfile('test.pid')
|
pidfile = gunicorn.pidfile.Pidfile('test.pid')
|
||||||
assert pidfile.validate() == 1
|
assert pidfile.validate() == 1
|
||||||
|
assert kill.called
|
||||||
|
|
||||||
|
|
||||||
@mock.patch(builtin('open'), new_callable=mock.mock_open, read_data='a')
|
@mock.patch(builtin('open'), new_callable=mock.mock_open, read_data='a')
|
||||||
|
|||||||
@ -74,7 +74,7 @@ class request(object):
|
|||||||
yield lines[:pos+2]
|
yield lines[:pos+2]
|
||||||
lines = lines[pos+2:]
|
lines = lines[pos+2:]
|
||||||
pos = lines.find(b"\r\n")
|
pos = lines.find(b"\r\n")
|
||||||
if len(lines):
|
if lines:
|
||||||
yield lines
|
yield lines
|
||||||
|
|
||||||
def send_bytes(self):
|
def send_bytes(self):
|
||||||
@ -137,7 +137,7 @@ class request(object):
|
|||||||
def match_read(self, req, body, sizes):
|
def match_read(self, req, body, sizes):
|
||||||
data = self.szread(req.body.read, sizes)
|
data = self.szread(req.body.read, sizes)
|
||||||
count = 1000
|
count = 1000
|
||||||
while len(body):
|
while body:
|
||||||
if body[:len(data)] != data:
|
if body[:len(data)] != data:
|
||||||
raise AssertionError("Invalid body data read: %r != %r" % (
|
raise AssertionError("Invalid body data read: %r != %r" % (
|
||||||
data, body[:len(data)]))
|
data, body[:len(data)]))
|
||||||
@ -148,9 +148,9 @@ class request(object):
|
|||||||
if count <= 0:
|
if count <= 0:
|
||||||
raise AssertionError("Unexpected apparent EOF")
|
raise AssertionError("Unexpected apparent EOF")
|
||||||
|
|
||||||
if len(body):
|
if body:
|
||||||
raise AssertionError("Failed to read entire body: %r" % body)
|
raise AssertionError("Failed to read entire body: %r" % body)
|
||||||
elif len(data):
|
elif data:
|
||||||
raise AssertionError("Read beyond expected body: %r" % data)
|
raise AssertionError("Read beyond expected body: %r" % data)
|
||||||
data = req.body.read(sizes())
|
data = req.body.read(sizes())
|
||||||
if data:
|
if data:
|
||||||
@ -159,7 +159,7 @@ class request(object):
|
|||||||
def match_readline(self, req, body, sizes):
|
def match_readline(self, req, body, sizes):
|
||||||
data = self.szread(req.body.readline, sizes)
|
data = self.szread(req.body.readline, sizes)
|
||||||
count = 1000
|
count = 1000
|
||||||
while len(body):
|
while body:
|
||||||
if body[:len(data)] != data:
|
if body[:len(data)] != data:
|
||||||
raise AssertionError("Invalid data read: %r" % data)
|
raise AssertionError("Invalid data read: %r" % data)
|
||||||
if b'\n' in data[:-1]:
|
if b'\n' in data[:-1]:
|
||||||
@ -170,9 +170,9 @@ class request(object):
|
|||||||
count -= 1
|
count -= 1
|
||||||
if count <= 0:
|
if count <= 0:
|
||||||
raise AssertionError("Apparent unexpected EOF")
|
raise AssertionError("Apparent unexpected EOF")
|
||||||
if len(body):
|
if body:
|
||||||
raise AssertionError("Failed to read entire body: %r" % body)
|
raise AssertionError("Failed to read entire body: %r" % body)
|
||||||
elif len(data):
|
elif data:
|
||||||
raise AssertionError("Read beyond expected body: %r" % data)
|
raise AssertionError("Read beyond expected body: %r" % data)
|
||||||
data = req.body.readline(sizes())
|
data = req.body.readline(sizes())
|
||||||
if data:
|
if data:
|
||||||
@ -190,7 +190,7 @@ class request(object):
|
|||||||
raise AssertionError("Invalid body data read: %r != %r" % (
|
raise AssertionError("Invalid body data read: %r != %r" % (
|
||||||
line, body[:len(line)]))
|
line, body[:len(line)]))
|
||||||
body = body[len(line):]
|
body = body[len(line):]
|
||||||
if len(body):
|
if body:
|
||||||
raise AssertionError("Failed to read entire body: %r" % body)
|
raise AssertionError("Failed to read entire body: %r" % body)
|
||||||
data = req.body.readlines(sizes())
|
data = req.body.readlines(sizes())
|
||||||
if data:
|
if data:
|
||||||
@ -207,7 +207,7 @@ class request(object):
|
|||||||
raise AssertionError("Invalid body data read: %r != %r" % (
|
raise AssertionError("Invalid body data read: %r != %r" % (
|
||||||
line, body[:len(line)]))
|
line, body[:len(line)]))
|
||||||
body = body[len(line):]
|
body = body[len(line):]
|
||||||
if len(body):
|
if body:
|
||||||
raise AssertionError("Failed to read entire body: %r" % body)
|
raise AssertionError("Failed to read entire body: %r" % body)
|
||||||
try:
|
try:
|
||||||
data = six.next(iter(req.body))
|
data = six.next(iter(req.body))
|
||||||
@ -254,7 +254,7 @@ class request(object):
|
|||||||
p = RequestParser(cfg, sender())
|
p = RequestParser(cfg, sender())
|
||||||
for req in p:
|
for req in p:
|
||||||
self.same(req, sizer, matcher, cases.pop(0))
|
self.same(req, sizer, matcher, cases.pop(0))
|
||||||
assert len(cases) == 0
|
assert not cases
|
||||||
|
|
||||||
def same(self, req, sizer, matcher, exp):
|
def same(self, req, sizer, matcher, exp):
|
||||||
assert req.method == exp["method"]
|
assert req.method == exp["method"]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user