




热更新配置的本质是主动监听并重新加载配置而非依赖Python模块重载。需用watchdog监听文件变化并去抖,或轮询Consul等外部源校验版本,同时解耦配置存储与使用,通过函数式访问或原子替换快照确保线程安全。
Python 进程启动后,配置通常只在初始化时加载一次。所谓“热更新”,不是让 Python 自动重载模块或变量,而是主动监听文件/数据库/远程服务的变化,并在检测到变更时重新解析、校验、合并配置,再通知业务逻辑使用新值。关键在于控制权在你自己手里,而不是依赖语言级的 reload 机制——importlib.reload 对配置模块效果差、副作用大,不推荐用于生产。
适用于本地 yaml、json、toml 等静态配置文件场景。watchdog 提供跨平台的文件系统事件监听,比轮询更轻量、及时。
pip install watchdog
modified 事件,建议加 100–500ms 去抖(例如用 threading.Timer 延迟处理)yaml.YAMLError、json.JSONDecodeError 等并打日志,保留旧配置继续运行示例核心逻辑:
from watchdog.observers import Observer from watchdog.events import FileSystemEventHandlerclass ConfigReloader(FileSystemEventHandler): def init(self, config_path, load_func): self.config_path = config_path self.load_func = load_func # 接收一个无参函数,负责重新加载并返回 dict
def on_modified(self, event): if event.src_path == self.config_path: try: new_cfg = self.load_func() apply_new_config(new_cfg) # 你自己的应用逻辑 except Exception as e: logger.error(f"Config reload failed: {e}")从环境变量或 Consul 等外部源拉取时,需主动轮询+缓存校验
环境变量无法监听变化,Consul/Etcd 的 watch 接口虽支持长连接,但 Python 客户端(如
python-consul)默认不自动重连或兜底。所以更稳妥的做法是定时拉取 + ETag/版本号比对。
5s),避免压垮配置中心;也不宜过长(如 60s),影响更新时效404 或空值时不应覆盖现有配置functools.lru_cache 缓存解析结果可减少重复计算,但注意清除策略(例如带 TTL 的自定义缓存)os.environ.get("CONFIG_ENV") 读环境变量,热更新只能靠父进程重设——实际不可行,应改用中间层封装(如 get_config("timeout") 函数内部查环境变量+fallback 到文件)很多热更新失败,不是因为没监听到变化,而是业务代码直接引用了全局字典的某个字段,比如 CFG["db"]["timeout"]。一旦 CFG 被整体替换,旧引用就断了;更糟的是多线程下可能读到部分更新的状态。
get_db_timeout(),内部每次从当前配置快照取值types.SimpleNamespace 或 dataclasses 构建不可变快照,更新时原子替换整个实例(配合 threading.RLock 保护读写)mmap)+ 信号通知最难处理的其实是状态依赖型配置——比如连接池大小变了,旧连接要不要关、新请求走新池还是旧池
