diff --git a/CHANGELOG.md b/CHANGELOG.md index 63b50fc..2e5ccb3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # 更新日志 (CHANGELOG) +## [v4.8.1] - feat(traceability): 实现全链路 TraceID 追踪,增强初始化韧性与去重拦截 +* **✨ 追踪性增强**: 实现全链路 TraceID 注入。现在所有插件日志均会自动带上任务唯一的 `trace_id` 前缀,且所有发送的图片报告及其重试消息均在该 `Caption` 下包含 `[ID: trace_id]` 标签,实现任务执行全流程透明化。 +* **🛠️ 健壮性增强**: 重构插件初始化流。针对平台加载延迟问题,延长初始化等待时间,并强制注册定时任务;在分析任务执行前增加“临门一脚”的平台自动发现补救机制,确保懒加载环境下任务不丢失。 +* **🐛 去重优化**: 强化 OneBot 适配器的检查去重逻辑。尝试支持基于 TraceID 的精确匹配拦截,有效防止因适配器超时导致的图片重复发送,并优化了多账号下的身份同步。 + ## [v4.8.0] - perf(concurrency): 实现群聊分析任务锁及全局资源并发限流控制,增强重试管理器 * **🛠️ 健壮性增强**: 在应用服务层实现基于群组和任务类型的异步锁,使用 asynccontextmanager 生成器函数确保同一群聊在同一时间只能执行一个分析任务。 * **🐛 Bug 修复**: 尝试增强重试管理器,增加 TraceID 观测重试链路具体情况,增强去重判断逻辑,最终目标是解决黑名单模式下向所有群发送而偶尔出现报告重复发送的 Bug(仍有待验证) diff --git a/main.py b/main.py index e2a2843..bf3502a 100644 --- a/main.py +++ b/main.py @@ -12,10 +12,10 @@ from astrbot.api import AstrBotConfig, logger as astrbot_logger from astrbot.api.event import AstrMessageEvent, filter from astrbot.api.event.filter import PermissionType from astrbot.api.star import Context, Star +from astrbot.core.message.components import File from .src.utils.logger import logger from .src.utils.trace_context import TraceContext, TraceLogFilter -from astrbot.core.message.components import File from .src.application.commands.template_command_service import ( TemplateCommandService, @@ -140,6 +140,7 @@ class GroupDailyAnalysis(Star): ) self._initialized = False + self._discovery_run = False # 是否已尝试过运行发现逻辑 # 异步注册任务,处理插件重载情况 asyncio.create_task(self._run_initialization("Plugin Reload/Init")) @@ -153,13 +154,18 @@ class GroupDailyAnalysis(Star): async def _run_initialization(self, source: str): """统一初始化逻辑""" - if self._initialized: + # 如果已经成功发现过平台,且不是来自 Platform Loaded 的强制触发,则跳过 + if ( + self._initialized + and self.bot_manager + and self.bot_manager.get_platform_count() > 0 + and source != "Platform Loaded" + ): return # 稍微延迟,确保 context 和环境稳定 - await asyncio.sleep(2) - if self._initialized: # Double check after sleep - return + # 针对极少数环境,2秒可能不足以让平台管理器就绪,增加到 5秒 + await asyncio.sleep(5) try: # 注册 TraceID 过滤器 @@ -181,23 +187,26 @@ class GroupDailyAnalysis(Star): # 此时不强制修改 config,但可以记录日志 pass - # 初始化所有bot实例 - discovered = await self.bot_manager.initialize_from_config() - if discovered: - logger.info("Bot管理器初始化成功") + # 1. 尝试发现 bot 实例(即使暂时没有,后续任务触发时也会再扫一遍) + await self.bot_manager.initialize_from_config() + + # 2. 注册预览路由器 (WebUI 路由注册不依赖在线机器人) + if self.template_preview_router: await self.template_preview_router.ensure_handlers_registered( self.context ) - # 启动调度器 - self.auto_scheduler.schedule_jobs(self.context) - else: - logger.warning("Bot管理器初始化失败,未发现任何适配器") - # 始终启动重试管理器 - await self.retry_manager.start() + # 3. 强制注册定时分析任务 (确保 APScheduler 即使在空载时也有任务占位) + if self.auto_scheduler: + self.auto_scheduler.schedule_jobs(self.context) + + # 4. 始终启动重试管理器 + if self.retry_manager: + await self.retry_manager.start() self._initialized = True - logger.info("插件任务注册完成") + self._discovery_run = True + logger.info(f"插件任务注册完成 (来源: {source})") except Exception as e: logger.error(f"插件初始化失败: {e}", exc_info=True) @@ -430,7 +439,9 @@ class GroupDailyAnalysis(Star): trace_id = TraceContext.generate(prefix=f"manual_{group_id}") TraceContext.set(trace_id) - yield event.plain_result(f"🔍 正在启动跨平台分析引擎,正在拉取最近消息...\n[ID: {trace_id}]") + yield event.plain_result( + f"🔍 正在启动跨平台分析引擎,正在拉取最近消息...\n[ID: {trace_id}]" + ) try: # 调用 DDD 应用级服务 diff --git a/metadata.yaml b/metadata.yaml index 6ce6e24..5d0edea 100644 --- a/metadata.yaml +++ b/metadata.yaml @@ -1,7 +1,7 @@ name: astrbot_plugin_qq_group_daily_analysis # 这是你的插件的唯一识别名。 display_name: 群分析总结插件 # 插件的显示名称 desc: "[多平台接入开发中] 群日常分析总结插件 - 支持 QQ (aiocqhttp)、Telegram、Discord;生成精美的群聊分析报告,支持话题分析、用户形象、群聊圣经等功能" # 插件简短描述 -version: v4.8.0 # 插件版本号。格式:v1.1.1 或者 v1.1 +version: v4.8.1 # 插件版本号。格式:v1.1.1 或者 v1.1 author: SXP-Simon # 作者 astrbot_version: ">=4.16.0" support_platforms: diff --git a/src/infrastructure/scheduler/auto_scheduler.py b/src/infrastructure/scheduler/auto_scheduler.py index a7063c2..e1c06c1 100644 --- a/src/infrastructure/scheduler/auto_scheduler.py +++ b/src/infrastructure/scheduler/auto_scheduler.py @@ -763,23 +763,23 @@ class AutoScheduler: """ all_groups = set() - # 强制刷新一次 Bot 实例,确保最新的 Bot 被发现 + # 1. [韧性增强] 进入扫描前,尝试最后一次实时发现机器人 + # 这确保了即使冷启动初始化失败,定时任务触发时仍能刷新状态 if hasattr(self.bot_manager, "auto_discover_bot_instances"): try: await self.bot_manager.auto_discover_bot_instances() except Exception as e: - logger.warning(f"[AutoScheduler] 自动发现失败: {e}") + logger.warning(f"[AutoScheduler] 周期性扫描中的平台发现失败: {e}") bot_ids = list(self.bot_manager._bot_instances.keys()) adapter_ids = list(self.bot_manager._adapters.keys()) - # 调试模式下记录详细信息,INFO级别仅显示概览 - logger.debug(f"[AutoScheduler] Bot实例: {bot_ids}, 适配器: {adapter_ids}") - if not bot_ids: - logger.warning("[AutoScheduler] 自动发现后未找到任何Bot实例") + logger.warning("[AutoScheduler] 分析周期开启,但全局未发现任何在线 Bot。任务将跳过。") return [] + logger.info(f"[AutoScheduler] 正在扫描 {len(bot_ids)} 个平台的群聊资源...") + for platform_id, bot_instance in self.bot_manager._bot_instances.items(): # 检查该平台是否启用了此插件 if not self.bot_manager.is_plugin_enabled(