[v4.8.1] - feat(traceability): 实现全链路 TraceID 追踪,增强初始化韧性与去重拦截

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