Use the best available reloader when --reload is passed

Fixes #1422
This commit is contained in:
Berker Peksag 2017-01-13 23:29:03 +03:00
parent 91807e8b90
commit 577c3eb030
4 changed files with 34 additions and 45 deletions

View File

@ -300,8 +300,8 @@ Debugging
reload reload
~~~~~~ ~~~~~~
* ``--reload RELOADER_TYPE`` * ``--reload``
* ``off`` * ``False``
Restart workers when code changes. Restart workers when code changes.
@ -312,14 +312,13 @@ The reloader is incompatible with application preloading. When using a
paste configuration be sure that the server block does not import any paste configuration be sure that the server block does not import any
application code or the reload will not work as designed. application code or the reload will not work as designed.
When using this option, you can optionally specify whether you would The default behavior is to attempt inotify with a fallback to file
like to use file system polling or the kernel's inotify API to watch system polling. Generally, inotify should be preferred if available
for changes. Generally, inotify should be preferred if available because it consumes less system resources.
because it consumes less system resources. The default behavior (auto)
is to attempt inotify with a fallback to FS polling.
Note: In order to use the inotify reloader, you must have the 'inotify' .. note::
package installed. In order to use the inotify reloader, you must have the ``inotify``
package installed.
.. _spew: .. _spew:

View File

@ -496,20 +496,6 @@ def validate_hostport(val):
raise TypeError("Value must consist of: hostname:port") raise TypeError("Value must consist of: hostname:port")
def validate_reloader(val):
if val is None:
val = 'auto'
choices = ['auto', 'poll', 'inotify', 'off']
if val not in choices:
raise ConfigError(
'Invalid reloader type. Must be one of: %s' % choices
)
return val
def get_default_config_file(): def get_default_config_file():
config_path = os.path.join(os.path.abspath(os.getcwd()), config_path = os.path.join(os.path.abspath(os.getcwd()),
'gunicorn.conf.py') 'gunicorn.conf.py')
@ -828,11 +814,9 @@ class Reload(Setting):
name = "reload" name = "reload"
section = 'Debugging' section = 'Debugging'
cli = ['--reload'] cli = ['--reload']
validator = validate_reloader validator = validate_bool
const = 'auto' action = 'store_true'
default = 'off' default = False
meta = 'RELOADER_TYPE'
nargs = '?'
desc = '''\ desc = '''\
Restart workers when code changes. Restart workers when code changes.
@ -844,14 +828,13 @@ class Reload(Setting):
paste configuration be sure that the server block does not import any paste configuration be sure that the server block does not import any
application code or the reload will not work as designed. application code or the reload will not work as designed.
When using this option, you can optionally specify whether you would The default behavior is to attempt inotify with a fallback to file
like to use file system polling or the kernel's inotify API to watch system polling. Generally, inotify should be preferred if available
for changes. Generally, inotify should be preferred if available because it consumes less system resources.
because it consumes less system resources. The default behavior (auto)
is to attempt inotify with a fallback to FS polling.
Note: In order to use the inotify reloader, you must have the 'inotify' .. note::
package installed. In order to use the inotify reloader, you must have the ``inotify``
package installed.
''' '''

View File

@ -15,7 +15,7 @@ import traceback
from gunicorn import six from gunicorn import six
from gunicorn import util from gunicorn import util
from gunicorn.workers.workertmp import WorkerTmp from gunicorn.workers.workertmp import WorkerTmp
from gunicorn.reloader import preferred_reloader, Reloader, InotifyReloader from gunicorn.reloader import preferred_reloader
from gunicorn.http.errors import ( from gunicorn.http.errors import (
InvalidHeader, InvalidHeaderName, InvalidRequestLine, InvalidRequestMethod, InvalidHeader, InvalidHeaderName, InvalidRequestLine, InvalidRequestMethod,
InvalidHTTPVersion, LimitRequestLine, LimitRequestHeaders, InvalidHTTPVersion, LimitRequestLine, LimitRequestHeaders,
@ -111,7 +111,7 @@ class Worker(object):
self.init_signals() self.init_signals()
# start the reloader # start the reloader
if self.cfg.reload and self.cfg.reload != 'off': if self.cfg.reload:
def changed(fname): def changed(fname):
self.log.info("Worker reloading: %s modified", fname) self.log.info("Worker reloading: %s modified", fname)
self.alive = False self.alive = False
@ -119,14 +119,7 @@ class Worker(object):
time.sleep(0.1) time.sleep(0.1)
sys.exit(0) sys.exit(0)
if self.cfg.reload == 'poll': self.reloader = preferred_reloader(callback=changed)
reloader_cls = Reloader
elif self.cfg.reload == 'inotify':
reloader_cls = InotifyReloader
else:
reloader_cls = preferred_reloader
self.reloader = reloader_cls(callback=changed)
self.reloader.start() self.reloader.start()
self.load_wsgi() self.load_wsgi()

View File

@ -333,3 +333,17 @@ def test_cli_overrides_enviroment_variables_module(monkeypatch):
with AltArgs(["prog_name", "-c", cfg_file(), "--workers", "3"]): with AltArgs(["prog_name", "-c", cfg_file(), "--workers", "3"]):
app = NoConfigApp() app = NoConfigApp()
assert app.cfg.workers == 3 assert app.cfg.workers == 3
@pytest.mark.parametrize("options, expected", [
(["myapp:app"], False),
(["--reload", "myapp:app"], True),
(["--reload", "--", "myapp:app"], True),
(["--reload", "-w 2", "myapp:app"], True),
])
def test_reload(options, expected):
cmdline = ["prog_name"]
cmdline.extend(options)
with AltArgs(cmdline):
app = NoConfigApp()
assert app.cfg.reload == expected