Skip to content

Commit 59e9f06

Browse files
committed
fix: 移除发送重试模块
1 parent 47eeff3 commit 59e9f06

9 files changed

Lines changed: 151 additions & 690 deletions

File tree

main.py

Lines changed: 13 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@
4545
)
4646
from .src.infrastructure.reporting.generators import ReportGenerator
4747
from .src.infrastructure.scheduler.auto_scheduler import AutoScheduler
48-
from .src.infrastructure.scheduler.retry import RetryManager
4948
from .src.shared.trace_context import TraceContext, TraceLogFilter
5049
from .src.utils.logger import logger
5150
from .src.utils.pdf_utils import PDFInstaller
@@ -72,7 +71,6 @@ class GroupDailyAnalysis(Star):
7271
template_command_service: TemplateCommandService
7372
telegram_template_preview_handler: TelegramTemplatePreviewHandler
7473
template_preview_router: TemplatePreviewRouter
75-
retry_manager: RetryManager
7674
auto_scheduler: AutoScheduler
7775
message_sender: MessageSender
7876

@@ -145,18 +143,12 @@ def __init__(self, context: Context, config: AstrBotConfig):
145143
handlers=[self.telegram_template_preview_handler]
146144
)
147145

148-
# 调度与重试
149-
self.retry_manager = RetryManager(
150-
self.bot_manager, self.html_render, self.report_generator
151-
)
152-
self.message_sender = MessageSender(
153-
self.bot_manager, self.config_manager, self.retry_manager
154-
)
146+
# 调度与发送
147+
self.message_sender = MessageSender(self.bot_manager, self.config_manager)
155148
self.auto_scheduler = AutoScheduler(
156149
self.config_manager,
157150
self.analysis_service,
158151
self.bot_manager,
159-
self.retry_manager,
160152
self.report_generator,
161153
self.html_render,
162154
plugin_instance=self,
@@ -239,10 +231,6 @@ async def _run_initialization(self, source: str):
239231
if self.auto_scheduler:
240232
self.auto_scheduler.schedule_jobs(self.context)
241233

242-
# 4. 始终启动重试管理器
243-
if self.retry_manager:
244-
await self.retry_manager.start()
245-
246234
self._initialized = True
247235
self._discovery_run = True
248236
logger.info(f"插件任务注册完成 (来源: {source})")
@@ -278,9 +266,6 @@ async def terminate(self):
278266
logger.debug("正在停止自动调度器...")
279267
self.auto_scheduler.unschedule_jobs(self.context)
280268

281-
if self.retry_manager:
282-
await self.retry_manager.stop()
283-
284269
if self.template_preview_router:
285270
await self.template_preview_router.unregister_handlers()
286271

@@ -625,23 +610,16 @@ async def nickname_getter(user_id: str) -> str | None:
625610

626611
if image_url:
627612
caption = TraceContext.make_report_caption()
628-
await adapter.send_image(group_id, image_url, caption=caption)
629-
await self._try_upload_image(group_id, image_url, platform_id)
630-
elif html_content:
631-
yield event.plain_result("⚠️ 群分析报告图片发送失败,自动重试中。")
632-
caption = TraceContext.make_report_caption()
633-
await self.retry_manager.add_task(
634-
html_content,
635-
analysis_result,
636-
group_id,
637-
platform_id,
638-
caption=caption,
639-
)
640-
else:
641-
text_report = self.report_generator.generate_text_report(
642-
analysis_result
643-
)
644-
yield event.plain_result(f"⚠️ 图片生成失败,回退文本:\n\n{text_report}")
613+
sent = await adapter.send_image(group_id, image_url, caption=caption)
614+
if sent:
615+
await self._try_upload_image(group_id, image_url, platform_id)
616+
return # 成功发送
617+
618+
# 如果图片生成或发送失败,直接回退到文本
619+
logger.warning(f"图片报告发送失败,正在发送文本回退报告。群: {group_id}")
620+
text_report = self.report_generator.generate_text_report(analysis_result)
621+
await adapter.send_text_report(group_id, text_report)
622+
return
645623

646624
elif output_format == "pdf":
647625
pdf_path = await self.report_generator.generate_pdf_report(
@@ -694,8 +672,7 @@ async def nickname_getter(user_id: str) -> str | None:
694672

695673
else:
696674
text_report = self.report_generator.generate_text_report(analysis_result)
697-
if not await adapter.send_text(group_id, text_report):
698-
yield event.plain_result(text_report)
675+
await adapter.send_text_report(group_id, text_report)
699676

700677
@filter.command("设置格式", alias={"set_format"})
701678
@filter.permission_type(PermissionType.ADMIN)

src/infrastructure/messaging/message_sender.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,9 @@ class MessageSender:
1212
封装了 PlatformAdapter 的底层调用,提供更高层的发送接口
1313
"""
1414

15-
def __init__(self, bot_manager, config_manager, retry_manager):
15+
def __init__(self, bot_manager, config_manager):
1616
self.bot_manager = bot_manager
1717
self.config_manager = config_manager
18-
self.retry_manager = retry_manager
1918

2019
async def send_text(
2120
self, group_id: str, text: str, platform_id: str | None = None

src/infrastructure/platform/adapters/discord_adapter.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ async def fetch_messages(
124124
list[UnifiedMessage]: 统一格式的消息对象列表
125125
"""
126126
if not discord:
127-
logger.error("Discord module (py-cord) not found. Cannot fetch messages.")
127+
logger.error("未找到 Discord 模块 (py-cord),无法拉取历史消息。")
128128
return []
129129

130130
try:

src/infrastructure/platform/adapters/lark_adapter.py

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -857,23 +857,6 @@ async def send_file(
857857
logger.error(f"飞书文件发送失败: {e}")
858858
return False
859859

860-
async def send_forward_msg(self, group_id: str, nodes: list[dict]) -> bool:
861-
if not nodes:
862-
return True
863-
chunks: list[str] = ["📊 群分析报告摘要"]
864-
for node in nodes:
865-
data = node.get("data", node)
866-
name = str(data.get("name", "AstrBot"))
867-
content = data.get("content", "")
868-
if isinstance(content, list):
869-
text_parts = []
870-
for seg in content:
871-
if isinstance(seg, dict) and seg.get("type") == "text":
872-
text_parts.append(str(seg.get("data", {}).get("text", "")))
873-
content = "".join(text_parts)
874-
chunks.append(f"[{name}] {content}")
875-
return await self.send_text(group_id, "\n".join(chunks))
876-
877860
async def get_group_info(self, group_id: str) -> UnifiedGroup | None:
878861
if not self._lark_client or not self._lark_client.im:
879862
return None

src/infrastructure/platform/adapters/onebot_adapter.py

Lines changed: 15 additions & 154 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
MessageContentType,
2323
UnifiedMessage,
2424
)
25-
from ....shared.trace_context import REPORT_CAPTION_PATTERN
2625
from ....utils.logger import logger
2726
from ..base import PlatformAdapter
2827

@@ -494,7 +493,7 @@ async def send_image(
494493
"""
495494
try:
496495
use_base64 = False
497-
plugin = self.config.get("plugin_instance") if self.config else None
496+
plugin: Any = self.config.get("plugin_instance") if self.config else None
498497
if plugin and hasattr(plugin, "config_manager"):
499498
use_base64 = plugin.config_manager.get_enable_base64_image()
500499

@@ -574,150 +573,16 @@ async def send_image(
574573
logger.info(f"Base64 回退模式发送图片成功: 群 {group_id}")
575574
return True
576575

577-
except Exception as e:
578-
# 识别 OneBot 的“假失败”情况:如果由于图片过大导致超时,其实图片往往已在后台由 OneBot 自动重传并最终会成功。
579-
error_str = str(e).lower()
580-
# 判定为“疑似成功”的特征:超时、1200、网络错误
581-
is_potential_success = (
582-
"timeout" in error_str or "1200" in error_str or "网络错误" in error_str
576+
await self.bot.call_action(
577+
"send_group_msg",
578+
group_id=int(group_id),
579+
message=message,
583580
)
581+
logger.info(f"Base64 回退模式发送图片成功: 群 {group_id}")
582+
return True
584583

585-
if is_potential_success:
586-
logger.warning(
587-
f"OneBot 发送群 {group_id} 图片出现疑似超时 ({e})。 "
588-
"进入多轮观察期,尝试通过历史回显核实..."
589-
)
590-
591-
# Multi-stage observation. Some OneBot implementations commit
592-
# history with delay after timeout-like errors.
593-
observe_windows = (10, 20, 30)
594-
for wait_seconds in observe_windows:
595-
await asyncio.sleep(wait_seconds)
596-
if await self.was_image_sent_recently(
597-
group_id, seconds=420, token=caption
598-
):
599-
logger.info(
600-
f"[OneBot] [真相拦截] 群 {group_id}{wait_seconds}s 观察后确认已送达,拦截重试。"
601-
)
602-
return True
603-
604-
return False # 没找回,返回 False,由上层 RetryManager 接管(带 20s 延迟观察期)
605-
606-
logger.error(f"OneBot 图片发送最终失败: {e}")
607-
return False
608-
609-
async def was_image_sent_recently(
610-
self, group_id: str, seconds: int = 60, token: str | None = None
611-
) -> bool:
612-
"""
613-
[真相检查] 检查最近 X 秒内,机器人是否已经向该群发送过图片。
614-
用于判断之前的“超时/1200”错误是否其实已经在后台发送成功。
615-
"""
616-
try:
617-
# 1. 获取最近的消息历史 (OneBot 标准 API)
618-
try:
619-
history = await self.bot.call_action(
620-
"get_group_msg_history",
621-
group_id=int(group_id),
622-
count=100, # 增大扫描深度以应对高频群聊
623-
)
624-
except Exception as e:
625-
logger.warning(
626-
f"[OneBot] was_image_sent_recently: get_group_msg_history 失败 (可能 API 繁忙): {e}"
627-
)
628-
return False # API 失败时,我们保持谨慎,但不阻止重试
629-
630-
if not history or "messages" not in history:
631-
messages = history if isinstance(history, list) else []
632-
else:
633-
messages = history["messages"]
634-
635-
# 2. 逆序检查
636-
import time
637-
638-
now = time.time()
639-
# 1. 优先从内存缓存中获取机器人 ID
640-
self_id = self.bot_self_ids[0] if self.bot_self_ids else ""
641-
642-
if not self_id:
643-
# 尝试从 bot 实例中获取多个可能的 ID 属性
644-
self_id = (
645-
str(getattr(self.bot, "self_id", ""))
646-
or str(getattr(self.bot, "uin", ""))
647-
or str(getattr(self.bot, "user_id", ""))
648-
)
649-
650-
if not self_id:
651-
# 最后的 API 兜底:尝试从 login_info 获取
652-
try:
653-
login_info = await self.bot.call_action("get_login_info")
654-
if login_info and "user_id" in login_info:
655-
self_id = str(login_info["user_id"])
656-
# 更新缓存,下次无需重复请求
657-
if self_id not in self.bot_self_ids:
658-
self.bot_self_ids.append(self_id)
659-
logger.info(f"[OneBot] 成功通过 API 获取到机器人 ID: {self_id}")
660-
except Exception as e:
661-
logger.debug(
662-
f"[OneBot] was_image_sent_recently: get_login_info API 调用失败: {e}"
663-
)
664-
665-
if not self_id:
666-
logger.warning(
667-
"[OneBot] was_image_sent_recently: 无法确定机器人 ID,历史回显校验可能不准确"
668-
)
669-
670-
# [优化] 从 Caption 中提取基于时间戳的去重 Token
671-
search_token = None
672-
if token:
673-
match = REPORT_CAPTION_PATTERN.search(token)
674-
if match:
675-
search_token = match.group(0) # 例如 "| 03-12 17:33:20"
676-
677-
for msg in reversed(messages):
678-
msg_time = msg.get("time", 0)
679-
# 只检查约定时间范围内的消息
680-
if now - msg_time > seconds:
681-
break
682-
683-
# 检查发送者是否是机器人自己
684-
user_id = str(
685-
msg.get("user_id", msg.get("sender", {}).get("user_id", ""))
686-
)
687-
if user_id not in self.bot_self_ids:
688-
# 如果内存中没有,尝试最后一次实时提取作为兜底
689-
if not self_id or user_id != self_id:
690-
continue
691-
692-
# 检查消息内容是否包含图片
693-
raw_message = msg.get("message", [])
694-
# 适配字符串形式或列表形式的消息
695-
msg_str = str(raw_message)
696-
697-
has_image = "[CQ:image" in msg_str or '"type": "image"' in msg_str
698-
699-
if has_image:
700-
if search_token:
701-
# 精确匹配 TraceID
702-
if search_token in msg_str:
703-
logger.info(
704-
f"[OneBot] [真相检查] 发现匹配 ID ({search_token}) 的历史图片。拦截重复发送。群: {group_id}"
705-
)
706-
return True
707-
else:
708-
logger.debug(
709-
f"[OneBot] [真相检查] 发现机器人发送的图片,但 ID 不匹配。跳过。群: {group_id}"
710-
)
711-
else:
712-
# 广义匹配(回退模式)
713-
logger.info(
714-
f"[OneBot] [真相检查] 发现近期发送过的图片回显 (广义匹配)。无需重试。群: {group_id}"
715-
)
716-
return True
717-
718-
return False
719584
except Exception as e:
720-
logger.debug(f"回显自检失败: {e}")
585+
logger.error(f"OneBot 图片发送最终失败: {e}")
721586
return False
722587

723588
async def send_file(
@@ -761,10 +626,13 @@ async def send_file(
761626
file=file_b64,
762627
name=filename or os.path.basename(file_path),
763628
)
764-
logger.info(f"Base64 回退模式发送文件成功: {filename or file_path}")
765-
return True
629+
# ... 实现省略 ...
630+
logger.info(
631+
f"[OneBot] 文件发送成功(Base64 模式): {filename or file_path}"
632+
)
633+
return True
766634
except Exception as e:
767-
logger.error(f"OneBot 文件发送最终失败: {e}")
635+
logger.error(f"[OneBot] 文件发送最终失败: {e}")
768636
return False
769637

770638
async def send_forward_msg(
@@ -774,13 +642,6 @@ async def send_forward_msg(
774642
) -> bool:
775643
"""
776644
发送群合并转发消息。
777-
778-
Args:
779-
group_id (str): 目标群号
780-
nodes (list[dict]): 转发节点列表
781-
782-
Returns:
783-
bool: 是否发送成功
784645
"""
785646
if not hasattr(self.bot, "call_action"):
786647
return False
@@ -799,7 +660,7 @@ async def send_forward_msg(
799660
)
800661
return True
801662
except Exception as e:
802-
logger.warning(f"OneBot 发送合并转发消息失败: {e}")
663+
logger.warning(f"[OneBot] 发送合并转发消息失败: {e}")
803664
return False
804665

805666
# ==================== IGroupInfoRepository 实现 ====================

0 commit comments

Comments
 (0)