Skip to content

Commit a7ce8df

Browse files
authored
feat: implement retry mechanism for QQ Official API file uploads (#7430)
* feat: implement retry mechanism for QQ Official API file uploads * fix: update error logging message for media file upload retries
1 parent 0984895 commit a7ce8df

File tree

1 file changed

+50
-18
lines changed

1 file changed

+50
-18
lines changed

astrbot/core/platform/sources/qqofficial/qqofficial_message_event.py

Lines changed: 50 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import asyncio
22
import base64
3+
import logging
34
import os
45
import random
56
import uuid
@@ -15,6 +16,13 @@
1516
from botpy.http import Route
1617
from botpy.types import message
1718
from botpy.types.message import MarkdownPayload, Media
19+
from tenacity import (
20+
before_sleep_log,
21+
retry,
22+
retry_if_exception_type,
23+
stop_after_attempt,
24+
wait_exponential,
25+
)
1826

1927
from astrbot.api import logger
2028
from astrbot.api.event import AstrMessageEvent, MessageChain
@@ -44,6 +52,20 @@ def _patch_qq_botpy_formdata() -> None:
4452

4553
_patch_qq_botpy_formdata()
4654

55+
# Retry decorator for QQ Official API transient errors (HTTP 500/504)
56+
_qqofficial_retry = retry(
57+
retry=retry_if_exception_type(
58+
(
59+
botpy.errors.ServerError,
60+
botpy.errors.SequenceNumberError,
61+
)
62+
),
63+
stop=stop_after_attempt(3),
64+
wait=wait_exponential(multiplier=1, min=1, max=10),
65+
before_sleep=before_sleep_log(logger, logging.WARNING),
66+
reraise=True,
67+
)
68+
4769

4870
class QQOfficialMessageEvent(AstrMessageEvent):
4971
MARKDOWN_NOT_ALLOWED_ERROR = "不允许发送原生 markdown"
@@ -453,21 +475,26 @@ async def upload_group_and_c2c_image(
453475
"srv_send_msg": False,
454476
}
455477

456-
result = None
457-
if "openid" in kwargs:
458-
payload["openid"] = kwargs["openid"]
459-
route = Route("POST", "/v2/users/{openid}/files", openid=kwargs["openid"])
460-
result = await self.bot.api._http.request(route, json=payload)
461-
elif "group_openid" in kwargs:
462-
payload["group_openid"] = kwargs["group_openid"]
463-
route = Route(
464-
"POST",
465-
"/v2/groups/{group_openid}/files",
466-
group_openid=kwargs["group_openid"],
467-
)
468-
result = await self.bot.api._http.request(route, json=payload)
469-
else:
470-
raise ValueError("Invalid upload parameters")
478+
@_qqofficial_retry
479+
async def _do_upload():
480+
if "openid" in kwargs:
481+
payload["openid"] = kwargs["openid"]
482+
route = Route(
483+
"POST", "/v2/users/{openid}/files", openid=kwargs["openid"]
484+
)
485+
return await self.bot.api._http.request(route, json=payload)
486+
elif "group_openid" in kwargs:
487+
payload["group_openid"] = kwargs["group_openid"]
488+
route = Route(
489+
"POST",
490+
"/v2/groups/{group_openid}/files",
491+
group_openid=kwargs["group_openid"],
492+
)
493+
return await self.bot.api._http.request(route, json=payload)
494+
else:
495+
raise ValueError("Invalid upload parameters")
496+
497+
result = await _do_upload()
471498

472499
if not isinstance(result, dict):
473500
raise RuntimeError(
@@ -490,7 +517,7 @@ async def upload_group_and_c2c_media(
490517
) -> Media | None:
491518
"""上传媒体文件"""
492519
# 构建基础payload
493-
payload = {"file_type": file_type, "srv_send_msg": srv_send_msg}
520+
payload: dict = {"file_type": file_type, "srv_send_msg": srv_send_msg}
494521
if file_name:
495522
payload["file_name"] = file_name
496523

@@ -519,9 +546,12 @@ async def upload_group_and_c2c_media(
519546
else:
520547
return None
521548

549+
@_qqofficial_retry
550+
async def _do_upload():
551+
return await self.bot.api._http.request(route, json=payload)
552+
522553
try:
523-
# 使用底层HTTP请求
524-
result = await self.bot.api._http.request(route, json=payload)
554+
result = await _do_upload()
525555

526556
if result:
527557
if not isinstance(result, dict):
@@ -533,6 +563,8 @@ async def upload_group_and_c2c_media(
533563
file_info=result["file_info"],
534564
ttl=result.get("ttl", 0),
535565
)
566+
except (botpy.errors.ServerError, botpy.errors.SequenceNumberError):
567+
logger.error(f"上传媒体文件失败,共尝试3次后放弃: {file_source}")
536568
except Exception as e:
537569
logger.error(f"上传请求错误: {e}")
538570

0 commit comments

Comments
 (0)