Преглед на файлове

Fixed #30361 -- Increased the default timeout of watchman client to 5 seconds and made it customizable.

Made the default timeout of watchman client customizable via
DJANGO_WATCHMAN_TIMEOUT environment variable.
Jacob Green преди 6 години
родител
ревизия
ed3c59097a
променени са 5 файла, в които са добавени 22 реда и са изтрити 2 реда
  1. 1 0
      AUTHORS
  2. 3 2
      django/utils/autoreload.py
  3. 5 0
      docs/ref/django-admin.txt
  4. 4 0
      docs/releases/2.2.1.txt
  5. 9 0
      tests/utils_tests/test_autoreload.py

+ 1 - 0
AUTHORS

@@ -364,6 +364,7 @@ answer newbie questions, and generally made Django that much better:
     Jaap Roes <jaap.roes@gmail.com>
     Jack Moffitt <https://metajack.im/>
     Jacob Burch <jacobburch@gmail.com>
+    Jacob Green
     Jacob Kaplan-Moss <jacob@jacobian.org>
     Jakub Paczkowski <jakub@paczkowski.eu>
     Jakub Wilk <jwilk@jwilk.net>

+ 3 - 2
django/utils/autoreload.py

@@ -366,11 +366,12 @@ class WatchmanReloader(BaseReloader):
     def __init__(self):
         self.roots = defaultdict(set)
         self.processed_request = threading.Event()
+        self.client_timeout = int(os.environ.get('DJANGO_WATCHMAN_TIMEOUT', 5))
         super().__init__()
 
     @cached_property
     def client(self):
-        return pywatchman.client()
+        return pywatchman.client(timeout=self.client_timeout)
 
     def _watch_root(self, root):
         # In practice this shouldn't occur, however, it's possible that a
@@ -528,7 +529,7 @@ class WatchmanReloader(BaseReloader):
     def check_availability(cls):
         if not pywatchman:
             raise WatchmanUnavailable('pywatchman not installed.')
-        client = pywatchman.client(timeout=0.01)
+        client = pywatchman.client(timeout=0.1)
         try:
             result = client.capabilityCheck()
         except Exception:

+ 5 - 0
docs/ref/django-admin.txt

@@ -897,6 +897,11 @@ more robust change detection, and a reduction in power usage.
     for optimal performance. See the `watchman documentation`_ for information
     on how to do this.
 
+.. admonition:: Watchman timeout
+
+    The default timeout of ``Watchman`` client is 5 seconds. You can change it
+    by setting the ``DJANGO_WATCHMAN_TIMEOUT`` environment variable.
+
 .. _Watchman: https://facebook.github.io/watchman/
 .. _pywatchman: https://pypi.org/project/pywatchman/
 .. _watchman documentation: https://facebook.github.io/watchman/docs/config.html#ignore_dirs

+ 4 - 0
docs/releases/2.2.1.txt

@@ -55,3 +55,7 @@ Bugfixes
   :class:`~django.contrib.sessions.middleware.SessionMiddleware` subclasses,
   rather than requiring :mod:`django.contrib.sessions` to be in
   :setting:`INSTALLED_APPS` (:ticket:`30312`).
+
+* Increased the default timeout when using ``Watchman`` to 5 seconds to prevent
+  falling back to ``StatReloader`` on larger projects and made it customizable
+  via the ``DJANGO_WATCHMAN_TIMEOUT`` environment variable (:ticket:`30361`).

+ 9 - 0
tests/utils_tests/test_autoreload.py

@@ -558,6 +558,11 @@ def skip_unless_watchman_available():
 class WatchmanReloaderTests(ReloaderTests, IntegrationTests):
     RELOADER_CLS = autoreload.WatchmanReloader
 
+    def setUp(self):
+        super().setUp()
+        # Shorten the timeout to speed up tests.
+        self.reloader.client_timeout = 0.1
+
     def test_watch_glob_ignores_non_existing_directories_two_levels(self):
         with mock.patch.object(self.reloader, '_subscribe') as mocked_subscribe:
             self.reloader._watch_glob(self.tempdir / 'does_not_exist' / 'more', ['*'])
@@ -638,6 +643,10 @@ class WatchmanReloaderTests(ReloaderTests, IntegrationTests):
                     self.reloader.update_watches()
                 self.assertIsInstance(mocked_server_status.call_args[0][0], TestException)
 
+    @mock.patch.dict(os.environ, {'DJANGO_WATCHMAN_TIMEOUT': '10'})
+    def test_setting_timeout_from_environment_variable(self):
+        self.assertEqual(self.RELOADER_CLS.client_timeout, 10)
+
 
 @skipIf(on_macos_with_hfs(), "These tests do not work with HFS+ as a filesystem")
 class StatReloaderTests(ReloaderTests, IntegrationTests):