mod_wsgi自动代码重载监控脚本触发RuntimeError问题求助
使用mod_wsgi实现代码自动重载时遇到RuntimeError问题
在用mod_wsgi实现代码变更自动重载时,运行官方文档提供的监控脚本出现RuntimeError,错误提示遍历sys.modules.values()时字典键发生变更。尝试文档中的示例代码也会触发相同错误,调整跟踪文件后,有时能完成一次重载,有时完全无法运行,不清楚问题原因及解决办法,特求助。
官方监控脚本代码
from __future__ import print_function import os import sys import time import signal import threading import atexit try: import Queue as queue except ImportError: import queue _interval = 1.0 _times = {} _files = [] _running = False _queue = queue.Queue() _lock = threading.Lock() def _restart(path): _queue.put(True) prefix = 'monitor (pid=%d):' % os.getpid() print('%s Change detected to \'%s\'.' % (prefix, path), file=sys.stderr) print('%s Triggering process restart.' % prefix, file=sys.stderr) os.kill(os.getpid(), signal.SIGINT) def _modified(path): try: # If path doesn't denote a file and were previously # tracking it, then it has been removed or the file type # has changed so force a restart. If not previously # tracking the file then we can ignore it as probably # pseudo reference such as when file extracted from a # collection of modules contained in a zip file. if not os.path.isfile(path): return path in _times # Check for when file last modified. mtime = os.stat(path).st_mtime if path not in _times: _times[path] = mtime # Force restart when modification time has changed, even # if time now older, as that could indicate older file # has been restored. if mtime != _times[path]: return True except: # If any exception occured, likely that file has been # been removed just before stat(), so force a restart. return True return False def _monitor(): while 1: # Check modification times on all files in sys.modules. for module in sys.modules.values(): print(module) if not hasattr(module, '__file__'): continue path = getattr(module, '__file__') if not path: continue if os.path.splitext(path)[1] in ['.pyc', '.pyo', '.pyd']: path = path[:-1] if _modified(path): return _restart(path) # Check modification times on files which have # specifically been registered for monitoring. for path in _files: print(f'PATH: {path}') if _modified(path): return _restart(path) # Go to sleep for specified interval. try: return _queue.get(timeout=_interval) except: pass _thread = threading.Thread(target=_monitor) _thread.setDaemon(True) def _exiting(): try: _queue.put(True) except: pass _thread.join() atexit.register(_exiting) def track(path): if path not in _files: _files.append(path) def start(interval=1.0): global _interval if interval < _interval: _interval = interval global _running _lock.acquire() if not _running: prefix = 'monitor (pid=%d):' % os.getpid() print('%s Starting change monitor.' % prefix, file=sys.stderr) _running = True _thread.start() _lock.release()
错误日志
[Thu Feb 23 18:46:27.482446 2023] [wsgi:error] [pid 11279] Exception in thread Thread-1 (_monitor): [Thu Feb 23 18:46:27.482617 2023] [wsgi:error] [pid 11279] Traceback (most recent call last): [Thu Feb 23 18:46:27.482635 2023] [wsgi:error] [pid 11279] File "/usr/lib64/python3.10/threading.py", line 1016, in _bootstrap_inner [Thu Feb 23 18:46:27.482983 2023] [wsgi:error] [pid 11279] self.run() [Thu Feb 23 18:46:27.483002 2023] [wsgi:error] [pid 11279] File "/usr/lib64/python3.10/threading.py", line 953, in run [Thu Feb 23 18:46:27.483162 2023] [wsgi:error] [pid 11279] self._target(*self._args, **self._kwargs) [Thu Feb 23 18:46:27.483177 2023] [wsgi:error] [pid 11279] File "/srv/flask_app/flask_app/monitor.py", line 66, in _monitor [Thu Feb 23 18:46:27.483239 2023] [wsgi:error] [pid 11279] for module in sys.modules.values(): [Thu Feb 23 18:46:27.483263 2023] [wsgi:error] [pid 11279] RuntimeError: dictionary keys changed during iteration
调用监控脚本的代码
monitor.start(interval=1.0) for root, dirs, files in os.walk(os.path.dirname(__file__), topdown=False): for name in files: monitor.track(os.path.join(root, name))
内容的提问来源于stack exchange,提问作者Jakke
相关产品推荐
相关产品推荐

