Skip to content

Commit

Permalink
config: reload-extra without reload
Browse files Browse the repository at this point in the history
  • Loading branch information
pajod committed Aug 13, 2024
1 parent 903792f commit 2096e42
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 7 deletions.
9 changes: 8 additions & 1 deletion docs/source/settings.rst
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ The default behavior is to attempt inotify with a fallback to file
system polling. Generally, inotify should be preferred if available
because it consumes less system resources.

.. note::
If the application fails to load while this option is used,
the (potentially sensitive!) traceback will be shared in
the response to subsequent HTTP requests.
.. note::
In order to use the inotify reloader, you must have the ``inotify``
package installed.
Expand Down Expand Up @@ -114,10 +118,13 @@ Valid engines are:

**Default:** ``[]``

Extends :ref:`reload` option to also watch and reload on additional files
Alternative or extension to :ref:`reload` option to (also) watch
and reload on additional files
(e.g., templates, configurations, specifications, etc.).

.. versionadded:: 19.8
.. versionchanged:: 23.FIXME
Option no longer silently ignored if used without :ref:`reload`.

.. _spew:

Expand Down
9 changes: 8 additions & 1 deletion gunicorn/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -921,6 +921,10 @@ class Reload(Setting):
system polling. Generally, inotify should be preferred if available
because it consumes less system resources.
.. note::
If the application fails to load while this option is used,
the (potentially sensitive!) traceback will be shared in
the response to subsequent HTTP requests.
.. note::
In order to use the inotify reloader, you must have the ``inotify``
package installed.
Expand Down Expand Up @@ -956,10 +960,13 @@ class ReloadExtraFiles(Setting):
validator = validate_list_of_existing_files
default = []
desc = """\
Extends :ref:`reload` option to also watch and reload on additional files
Alternative or extension to :ref:`reload` option to (also) watch
and reload on additional files
(e.g., templates, configurations, specifications, etc.).
.. versionadded:: 19.8
.. versionchanged:: 23.FIXME
Option no longer silently ignored if used without :ref:`reload`.
"""


Expand Down
15 changes: 12 additions & 3 deletions gunicorn/reloader.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,21 @@


class Reloader(threading.Thread):
def __init__(self, extra_files=None, interval=1, callback=None):
def __init__(self, extra_files=None, interval=1, callback=None, auto_detect=False):
super().__init__()
self.daemon = True
self._extra_files = set(extra_files or ())
self._interval = interval
self._callback = callback
self._auto_detect = auto_detect

def add_extra_file(self, filename):
self._extra_files.add(filename)

def get_files(self):
if not self._auto_detect:
return self._extra_files

fnames = [
COMPILED_EXT_RE.sub('py', module.__file__)
for module in tuple(sys.modules.values())
Expand Down Expand Up @@ -71,12 +75,13 @@ class InotifyReloader(threading.Thread):
| inotify.constants.IN_MOVE_SELF | inotify.constants.IN_MOVED_FROM
| inotify.constants.IN_MOVED_TO)

def __init__(self, extra_files=None, callback=None):
def __init__(self, extra_files=None, callback=None, auto_detect=False):
super().__init__()
self.daemon = True
self._callback = callback
self._dirs = set()
self._watcher = Inotify()
self._auto_detect = auto_detect

for extra_file in extra_files:
self.add_extra_file(extra_file)
Expand All @@ -91,6 +96,9 @@ def add_extra_file(self, filename):
self._dirs.add(dirname)

def get_dirs(self):
if not self._auto_detect:
return set()

fnames = [
os.path.dirname(os.path.abspath(COMPILED_EXT_RE.sub('py', module.__file__)))
for module in tuple(sys.modules.values())
Expand All @@ -100,6 +108,7 @@ def get_dirs(self):
return set(fnames)

def run(self):
# FIXME: _watchers/_dirs inconsistent - latter gets reset
self._dirs = self.get_dirs()

for dirname in self._dirs:
Expand All @@ -117,7 +126,7 @@ def run(self):
else:

class InotifyReloader:
def __init__(self, extra_files=None, callback=None):
def __init__(self, extra_files=None, callback=None, auto_detect=False):
raise ImportError('You must have the inotify module installed to '
'use the inotify reloader')

Expand Down
4 changes: 2 additions & 2 deletions gunicorn/workers/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ def init_process(self):
self.init_signals()

# start the reloader
if self.cfg.reload:
if self.cfg.reload or self.cfg.reload_extra_files:
def changed(fname):
self.log.info("Worker reloading: %s modified", fname)
self.alive = False
Expand All @@ -130,7 +130,7 @@ def changed(fname):

reloader_cls = reloader_engines[self.cfg.reload_engine]
self.reloader = reloader_cls(extra_files=self.cfg.reload_extra_files,
callback=changed)
callback=changed, auto_detect=self.cfg.reload)

self.load_wsgi()
if self.reloader:
Expand Down

0 comments on commit 2096e42

Please sign in to comment.