Add support for --reload-engine

Currently, gunicorn automatically uses the preferred reloader (inotify
if present with fallback to polling). However, it would be useful in
some scenarios if users could force polling.

The solution for this is to add a new configuration option called
'reload_engine' which takes one of three options: ['auto', 'poll',
'inotify'].

Fixes #1459
This commit is contained in:
Mark Adams 2017-02-14 10:35:35 -06:00 committed by Berker Peksag
parent 34a624ff59
commit bc20bea7d9
4 changed files with 49 additions and 2 deletions

View File

@ -23,6 +23,7 @@ import shlex
from gunicorn import __version__
from gunicorn import _compat
from gunicorn.errors import ConfigError
from gunicorn.reloader import reloader_engines
from gunicorn import six
from gunicorn import util
@ -496,6 +497,13 @@ def validate_hostport(val):
raise TypeError("Value must consist of: hostname:port")
def validate_reload_engine(val):
if val not in reloader_engines:
raise ConfigError("Invalid reload_engine: %r" % val)
return val
def get_default_config_file():
config_path = os.path.join(os.path.abspath(os.getcwd()),
'gunicorn.conf.py')
@ -838,6 +846,26 @@ class Reload(Setting):
'''
class ReloadEngine(Setting):
name = "reload_engine"
section = "Debugging"
cli = ["--reload-engine"]
meta = "STRING"
validator = validate_reload_engine
default = "auto"
desc = """\
The implementation that should be used to power :ref:`reload`.
Valid engines are:
* 'auto'
* 'poll'
* 'inotify' (requires inotify)
.. versionadded:: 19.7
"""
class Spew(Setting):
name = "spew"
section = "Debugging"

View File

@ -115,3 +115,9 @@ if has_inotify:
preferred_reloader = InotifyReloader if has_inotify else Reloader
reloader_engines = {
'auto': preferred_reloader,
'poll': Reloader,
'inotify': InotifyReloader,
}

View File

@ -15,7 +15,7 @@ import traceback
from gunicorn import six
from gunicorn import util
from gunicorn.workers.workertmp import WorkerTmp
from gunicorn.reloader import preferred_reloader
from gunicorn.reloader import reloader_engines
from gunicorn.http.errors import (
InvalidHeader, InvalidHeaderName, InvalidRequestLine, InvalidRequestMethod,
InvalidHTTPVersion, LimitRequestLine, LimitRequestHeaders,
@ -119,7 +119,8 @@ class Worker(object):
time.sleep(0.1)
sys.exit(0)
self.reloader = preferred_reloader(callback=changed)
reloader_cls = reloader_engines[self.cfg.reload_engine]
self.reloader = reloader_cls(callback=changed)
self.reloader.start()
self.load_wsgi()

View File

@ -10,6 +10,7 @@ import pytest
from gunicorn import config
from gunicorn.app.base import Application
from gunicorn.errors import ConfigError
from gunicorn.workers.sync import SyncWorker
from gunicorn import glogging
from gunicorn.instrument import statsd
@ -152,6 +153,17 @@ def test_callable_validation():
pytest.raises(TypeError, c.set, "pre_fork", lambda x: True)
def test_reload_engine_validation():
c = config.Config()
assert c.reload_engine == "auto"
c.set('reload_engine', 'poll')
assert c.reload_engine == 'poll'
pytest.raises(ConfigError, c.set, "reload_engine", "invalid")
def test_callable_validation_for_string():
from os.path import isdir as testfunc
assert config.validate_callable(-1)("os.path.isdir") == testfunc