mirror of
https://github.com/frappe/gunicorn.git
synced 2026-01-14 11:09:11 +08:00
Here's the reproducer in Python 3.3:
$ gunicorn --paste paste.ini --reload
Then I got the following exception:
Exception in thread Thread-1:
Traceback (most recent call last):
File "/usr/local/lib/python3.3/threading.py", line 901, in _bootstrap_inner
self.run()
File "/home/berker/hacking/mediagoblin/venv3/lib/python3.3/site-packages/gunicorn/reloader.py", line 41, in run
for filename in self.get_files():
File "/home/berker/hacking/mediagoblin/venv3/lib/python3.3/site-packages/gunicorn/reloader.py", line 29, in get_files
for module in sys.modules.values()
File "/home/berker/hacking/mediagoblin/venv3/lib/python3.3/site-packages/gunicorn/reloader.py", line 28, in <listcomp>
re.sub('py[co]$', 'py', module.__file__)
RuntimeError: dictionary changed size during iteration
54 lines
1.5 KiB
Python
54 lines
1.5 KiB
Python
# -*- coding: utf-8 -
|
|
#
|
|
# This file is part of gunicorn released under the MIT license.
|
|
# See the NOTICE for more information.
|
|
|
|
import os
|
|
import re
|
|
import sys
|
|
import time
|
|
import threading
|
|
|
|
|
|
class Reloader(threading.Thread):
|
|
def __init__(self, extra_files=None, interval=1, callback=None):
|
|
super(Reloader, self).__init__()
|
|
self.setDaemon(True)
|
|
self._extra_files = set(extra_files or ())
|
|
self._extra_files_lock = threading.RLock()
|
|
self._interval = interval
|
|
self._callback = callback
|
|
|
|
def add_extra_file(self, filename):
|
|
with self._extra_files_lock:
|
|
self._extra_files.add(filename)
|
|
|
|
def get_files(self):
|
|
fnames = [
|
|
re.sub('py[co]$', 'py', module.__file__)
|
|
for module in list(sys.modules.values())
|
|
if hasattr(module, '__file__')
|
|
]
|
|
|
|
with self._extra_files_lock:
|
|
fnames.extend(self._extra_files)
|
|
|
|
return fnames
|
|
|
|
def run(self):
|
|
mtimes = {}
|
|
while True:
|
|
for filename in self.get_files():
|
|
try:
|
|
mtime = os.stat(filename).st_mtime
|
|
except OSError:
|
|
continue
|
|
old_time = mtimes.get(filename)
|
|
if old_time is None:
|
|
mtimes[filename] = mtime
|
|
continue
|
|
elif mtime > old_time:
|
|
if self._callback:
|
|
self._callback(filename)
|
|
time.sleep(self._interval)
|