feat: 添加守护线程版本的队列监听器以避免阻塞退出,优化配置初始化逻辑,改进消息构建中的用户信息处理

This commit is contained in:
Windpicker-owo
2025-11-27 14:06:17 +08:00
parent 4af6a5ec0c
commit 369639a8f1
4 changed files with 70 additions and 16 deletions

View File

@@ -17,6 +17,27 @@ from rich.console import Console
from rich.text import Text
from structlog.typing import EventDict, WrappedLogger
# 守护线程版本的队列监听器,防止退出时卡住
class DaemonQueueListener(QueueListener):
"""QueueListener 的工作线程作为守护进程运行,以避免阻塞关闭。"""
def _configure_listener(self):
super()._configure_listener()
if hasattr(self, "_thread") and self._thread is not None: # type: ignore[attr-defined]
self._thread.daemon = True # type: ignore[attr-defined]
def stop(self):
"""停止监听器,避免在退出时无限期阻塞。"""
try:
self._stop.set() # type: ignore[attr-defined]
self.enqueue_sentinel()
# join with timeout; if it does not finish we continue exit
if hasattr(self, "_thread") and self._thread is not None: # type: ignore[attr-defined]
self._thread.join(timeout=1.5) # type: ignore[attr-defined]
except Exception:
# best-effort; swallow errors on shutdown
pass
# 创建logs目录
LOG_DIR = Path("logs")
LOG_DIR.mkdir(exist_ok=True)
@@ -110,7 +131,7 @@ def _start_queue_logging(handlers: Sequence[logging.Handler]) -> QueueHandler |
_log_queue = SimpleQueue()
_queue_handler = StructlogQueueHandler(_log_queue)
_queue_listener = QueueListener(_log_queue, *handlers, respect_handler_level=True)
_queue_listener = DaemonQueueListener(_log_queue, *handlers, respect_handler_level=True)
_queue_listener.start()
return _queue_handler
@@ -120,7 +141,14 @@ def _stop_queue_logging():
global _log_queue, _queue_handler, _queue_listener
if _queue_listener is not None:
_queue_listener.stop()
try:
stopper = threading.Thread(target=_queue_listener.stop, name="log-queue-stop", daemon=True)
stopper.start()
stopper.join(timeout=3.0)
if stopper.is_alive():
print("[日志系统] 停止日志队列监听器超时,继续退出")
except Exception as e:
print(f"[日志系统] 停止日志队列监听器失败: {e}")
_queue_listener = None
_log_queue = None

View File

@@ -66,6 +66,11 @@ TEMPLATE_DIR = os.path.join(PROJECT_ROOT, "template")
# 对该字段的更新请严格参照语义化版本规范https://semver.org/lang/zh-CN/
MMC_VERSION = "0.13.0-alpha.3"
# 全局配置变量
_CONFIG_INITIALIZED = False
global_config: "Config | None" = None
model_config: "APIAdapterConfig | None" = None
def get_key_comment(toml_table, key):
# 获取key的注释如果有
@@ -546,12 +551,30 @@ def api_ada_load_config(config_path: str) -> APIAdapterConfig:
# 获取配置文件路径
logger.info(f"MaiCore当前版本: {MMC_VERSION}")
update_config()
update_model_config()
logger.info("正在品鉴配置文件...")
global_config = load_config(config_path=os.path.join(CONFIG_DIR, "bot_config.toml"))
model_config = api_ada_load_config(config_path=os.path.join(CONFIG_DIR, "model_config.toml"))
def initialize_configs_once() -> tuple[Config, APIAdapterConfig]:
"""
初始化配置文件,只执行一次。
"""
global _CONFIG_INITIALIZED, global_config, model_config
logger.info("非常的新鲜,非常的美味!")
if _CONFIG_INITIALIZED and global_config and model_config:
logger.debug("config.py 初始化已执行,跳过重复运行")
return global_config, model_config
logger.info(f"MaiCore当前版本: {MMC_VERSION}")
update_config()
update_model_config()
logger.info("正在品鉴配置文件...")
global_config = load_config(config_path=os.path.join(CONFIG_DIR, "bot_config.toml"))
model_config = api_ada_load_config(config_path=os.path.join(CONFIG_DIR, "model_config.toml"))
_CONFIG_INITIALIZED = True
return global_config, model_config
# 同一进程只执行一次初始化,避免重复生成或覆盖配置
global_config, model_config = initialize_configs_once()
logger.info("非常的新鲜,非常的美味!")

View File

@@ -67,12 +67,13 @@ class MainSystem:
# CoreSinkManager 和 MessageHandler 将在 initialize() 中创建
self.core_sink_manager: CoreSinkManager | None = None
self.message_handler = None
# 使用服务器
self.server: Server = get_global_server()
# 设置信号处理器用于优雅退出
self._shutting_down = False
self._cleanup_started = False
self._setup_signal_handlers()
# 存储清理任务的引用
@@ -201,9 +202,10 @@ class MainSystem:
async def _async_cleanup(self) -> None:
"""异步清理资源"""
if self._shutting_down:
if self._cleanup_started:
return
self._cleanup_started = True
self._shutting_down = True
logger.info("开始系统清理流程...")
@@ -637,7 +639,7 @@ MoFox_Bot(第三方修改版)
async def shutdown(self) -> None:
"""关闭系统组件"""
if self._shutting_down:
if self._cleanup_started:
return
logger.info("正在关闭MainSystem...")

View File

@@ -192,15 +192,16 @@ def _build_message_envelope(
timestamp: float,
) -> MessageEnvelope:
"""构建发送的 MessageEnvelope 数据结构"""
target_user_info = target_stream.user_info or bot_user_info
message_info: dict[str, Any] = {
"message_id": message_id,
"time": timestamp,
"platform": target_stream.platform,
"user_info": {
"user_id": bot_user_info.user_id,
"user_nickname": bot_user_info.user_nickname,
"user_cardname": getattr(bot_user_info, "user_cardname", None),
"platform": bot_user_info.platform,
"user_id": target_user_info.user_id,
"user_nickname": target_user_info.user_nickname,
"user_cardname": getattr(target_user_info, "user_cardname", None),
"platform": target_user_info.platform,
},
}