支持全局配置保存后立即应用到运行时
- 新增 Robot.apply_runtime_config 统一刷新邮件发送器、管理员列表与 LLM 运行时缓存\n- 新增 LLMRegistry.invalidate_cache 主动清理目录与 legacy 配置缓存\n- 后台保存全局配置与 LLM 目录后立即应用运行时配置,减少重启依赖
This commit is contained in:
@@ -13,6 +13,7 @@ import json
|
||||
import yaml
|
||||
import toml
|
||||
from utils.markdown_to_image import get_md2img_health_snapshot, warmup_md2img_browser_sync
|
||||
from utils.ai.llm_registry import LLMRegistry
|
||||
|
||||
# 创建系统信息蓝图
|
||||
system_bp = Blueprint('system', __name__)
|
||||
@@ -479,8 +480,13 @@ def update_system_config():
|
||||
|
||||
if getattr(server, "robot", None) and getattr(server.robot, "config", None):
|
||||
server.robot.config.reload()
|
||||
# 保存 YAML 后立刻把运行时依赖对象同步一遍,避免必须重启进程才能读到新值。
|
||||
server.robot.apply_runtime_config(reload_catalog=True)
|
||||
else:
|
||||
# 即便当前没有可用 robot 实例,也尽量把 LLM 路由缓存清掉,避免后续请求短时间内读旧值。
|
||||
LLMRegistry.invalidate_cache()
|
||||
|
||||
return jsonify({"success": True, "message": "全局配置已保存"})
|
||||
return jsonify({"success": True, "message": "全局配置已保存并应用到运行时"})
|
||||
except Exception as e:
|
||||
logger.error(f"保存系统配置失败: {e}")
|
||||
return jsonify({"success": False, "message": str(e)}), 500
|
||||
@@ -606,8 +612,12 @@ def update_system_llm_config():
|
||||
|
||||
if getattr(server, "robot", None) and getattr(server.robot, "config", None):
|
||||
server.robot.config.reload()
|
||||
# LLM 目录保存到 MySQL 后,需要主动失效运行时缓存,保证插件下一次调用直接走新目录。
|
||||
server.robot.apply_runtime_config(reload_catalog=True)
|
||||
else:
|
||||
LLMRegistry.invalidate_cache()
|
||||
|
||||
return jsonify({"success": True, "message": "全局 LLM 配置已保存"})
|
||||
return jsonify({"success": True, "message": "全局 LLM 配置已保存并应用到运行时"})
|
||||
except Exception as e:
|
||||
logger.error(f"保存全局 LLM 配置失败: {e}")
|
||||
return jsonify({"success": False, "message": str(e)}), 500
|
||||
|
||||
33
robot.py
33
robot.py
@@ -30,6 +30,7 @@ from utils.robot_cmd.robot_command import GroupBotManager, Feature, PermissionSt
|
||||
from utils.wechat.contact_manager import ContactManager
|
||||
from utils.wechat.member_monitor import ChatroomMemberMonitor
|
||||
from utils.wechat.message_to_db import MessageStorage
|
||||
from utils.ai.llm_registry import LLMRegistry
|
||||
from wechat_ipad import WechatAPIClient
|
||||
from wechat_ipad.models.message import WxMessage, MessageType
|
||||
|
||||
@@ -144,6 +145,38 @@ class Robot:
|
||||
GroupBotManager.admin_list = self.config.wx_config.get("admin", [])
|
||||
self.recent_msg_ids = deque(maxlen=20)
|
||||
|
||||
def apply_runtime_config(self, reload_catalog: bool = False) -> None:
|
||||
"""把最新全局配置应用到当前运行中的关键对象。
|
||||
|
||||
说明:
|
||||
1. `self.config.reload()` 只会刷新 Config 实例中的字段,不会自动更新启动时已构造的依赖对象;
|
||||
2. 这里集中处理“保存配置后希望立刻生效”的轻量刷新动作,避免为大多数改动走整进程重启;
|
||||
3. 该方法刻意不去重建 DB 连接、微信登录态、插件实例,尽量把影响范围控制在可热刷的配置项。
|
||||
"""
|
||||
# 邮件发送器在初始化时会拷贝 SMTP 参数,因此这里需要按最新配置重建一份实例。
|
||||
self.email_sender = EmailSender(
|
||||
smtp_server=self.config.email.get("smtp_server", "smtp.163.com"),
|
||||
smtp_port=self.config.email.get("smtp_port", 465),
|
||||
sender_email=self.config.email.get("sender_email", "bovine_liu@163.com"),
|
||||
sender_password=self.config.email.get("sender_password", "LTS9BhmX9XhS36QS")
|
||||
)
|
||||
|
||||
# 管理员列表走 GroupBotManager 的类级缓存;只 reload Config 不会自动回写到这里。
|
||||
GroupBotManager.admin_list = self.config.wx_config.get("admin", [])
|
||||
|
||||
# system_context 中保存的是 config 对象引用,reload 后插件读取到的是最新字段。
|
||||
# 但 LLMRegistry 自己还有一层短 TTL 缓存,因此保存全局 LLM 配置后需要显式清掉。
|
||||
if reload_catalog:
|
||||
self.llm_catalog_db.bootstrap_from_legacy_llm(self.config.llm)
|
||||
LLMRegistry.invalidate_cache()
|
||||
|
||||
self.LOG.info(
|
||||
"运行时配置已应用: "
|
||||
f"admin_count={len(GroupBotManager.admin_list)}, "
|
||||
f"email_sender={'ready' if self.email_sender else 'missing'}, "
|
||||
f"llm_cache_reloaded={reload_catalog}"
|
||||
)
|
||||
|
||||
def _cleanup_migrated_system_jobs(self):
|
||||
"""清理已经迁移到插件层的历史系统任务键。"""
|
||||
migrated_keys = [
|
||||
|
||||
@@ -24,6 +24,21 @@ class LLMRegistry:
|
||||
"legacy_llm": {},
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def invalidate_cache(cls) -> None:
|
||||
"""主动清空运行时缓存。
|
||||
|
||||
说明:
|
||||
1. 后台修改全局 YAML 或 MySQL 中的 LLM 目录后,旧缓存可能还在 3 秒有效期内;
|
||||
2. 对于“保存后立刻生效”的后台体验,主动失效比等待 TTL 自然过期更直接;
|
||||
3. 这里只清缓存,不做任何 IO,下一次 resolve/get_catalog 时会自动重新装载最新配置。
|
||||
"""
|
||||
cls._cache = {
|
||||
"cache_until": 0.0,
|
||||
"catalog": {},
|
||||
"legacy_llm": {},
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def get_root_config_path(cls) -> Path:
|
||||
return Path(__file__).resolve().parents[2] / "config.yaml"
|
||||
|
||||
Reference in New Issue
Block a user