Skip to content

Commit

Permalink
avoid large reload loops due to many files changing
Browse files Browse the repository at this point in the history
  • Loading branch information
mmerickel committed Feb 17, 2020
1 parent 597567c commit 102b4c0
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 13 deletions.
34 changes: 23 additions & 11 deletions src/hupper/reloader.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import re
import signal
import sys
import threading
import time

from .compat import glob
Expand Down Expand Up @@ -37,6 +38,8 @@ def __init__(self, callback, logger, ignore_files=None):
self.ignore_files = [
re.compile(fnmatch.translate(x)) for x in set(ignore_files or [])
]
self.lock = threading.Lock()
self.is_changed = False

def add_path(self, path):
# if the glob does not match any files then go ahead and pass
Expand All @@ -54,13 +57,19 @@ def stop(self):
self.monitor.join()

def file_changed(self, path):
if path not in self.changed_paths:
self.changed_paths.add(path)
self.logger.info('%s changed; reloading ...' % (path,))
self.callback(self.changed_paths)
with self.lock:
if path not in self.changed_paths:
self.logger.info('{} changed; reloading ...'.format(path))
self.changed_paths.add(path)

if not self.is_changed:
self.callback(self.changed_paths)
self.is_changed = True

def clear_changes(self):
self.changed_paths = set()
with self.lock:
self.changed_paths = set()
self.is_changed = False


class ControlSignal:
Expand Down Expand Up @@ -228,18 +237,20 @@ def handle_packet(packet):
packets.append(packet)
os.write(self.control_w, ControlSignal.WORKER_COMMAND)

self.monitor.clear_changes()

worker.start(handle_packet)
result = WorkerResult.WAIT
soft_kill = True

logger.info('Starting monitor for PID %s.' % worker.pid)
try:
# register the worker with the process group
self.process_group.add_child(worker.pid)

logger.info('Starting monitor for PID %s.' % worker.pid)
self.monitor.clear_changes()

while True:
# process all packets before moving on to signals to avoid
# missing any files that need to be watched
if packets:
cmd = packets.popleft()

Expand Down Expand Up @@ -267,7 +278,7 @@ def handle_packet(packet):
result = WorkerResult.RELOAD
break

elif cmd[0] == 'watch':
elif cmd[0] == 'watch_files':
for path in cmd[1]:
self.monitor.add_path(path)

Expand Down Expand Up @@ -315,8 +326,9 @@ def handle_packet(packet):
break

elif signal == ControlSignal.FILE_CHANGED:
result = WorkerResult.RELOAD
break
if self.monitor.is_changed:
result = WorkerResult.RELOAD
break

if worker.is_alive() and self.shutdown_interval:
if soft_kill:
Expand Down
4 changes: 2 additions & 2 deletions src/hupper/worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
class WatchSysModules(threading.Thread):
""" Poll ``sys.modules`` for imported modules."""

poll_interval = 1
poll_interval = 3
ignore_system_paths = True

def __init__(self, callback):
Expand Down Expand Up @@ -205,7 +205,7 @@ def __init__(self, pipe):

def watch_files(self, files):
files = [os.path.abspath(f) for f in files]
self.pipe.send(('watch', files))
self.pipe.send(('watch_files', files))

def trigger_reload(self):
self.pipe.send(('reload',))
Expand Down

0 comments on commit 102b4c0

Please sign in to comment.