From a6817d3e118d7376178c184fe3021cb924f51bd0 Mon Sep 17 00:00:00 2001 From: Zichao Lin Date: Thu, 2 Jul 2026 20:02:03 +0800 Subject: [PATCH] feat: add retry(10) on all network requests - New src/retry.py with configurable retry decorator - Applied @retry() to fetch_unseen_emails, mark_as_seen, summarize_email, and send_message - No backoff delay between retries --- src/ai_client.py | 2 ++ src/email_client.py | 3 +++ src/retry.py | 29 +++++++++++++++++++++++++++++ src/tg_bot.py | 2 ++ 4 files changed, 36 insertions(+) create mode 100644 src/retry.py diff --git a/src/ai_client.py b/src/ai_client.py index b6b6c39..d1e77fd 100644 --- a/src/ai_client.py +++ b/src/ai_client.py @@ -2,6 +2,7 @@ import json from typing import Any import requests from src.config import AIConfig +from src.retry import retry SYSTEM_PROMPT = """你是一个邮件摘要助手。请分析邮件内容并以 JSON 格式返回结构化摘要。 @@ -19,6 +20,7 @@ SYSTEM_PROMPT = """你是一个邮件摘要助手。请分析邮件内容并以 只返回 JSON,不要包含任何其他文字。""" +@retry() def summarize_email(ai_cfg: AIConfig, subject: str, sender: str, body: str) -> dict[str, Any]: content = f"发件人: {sender}\n主题: {subject}\n正文:\n{body[:4000]}" diff --git a/src/email_client.py b/src/email_client.py index 96e1379..8a5d54c 100644 --- a/src/email_client.py +++ b/src/email_client.py @@ -4,6 +4,7 @@ from email.header import decode_header from email.utils import parsedate_to_datetime from typing import Optional from src.config import EmailAccount +from src.retry import retry class Email: @@ -76,6 +77,7 @@ def _login_and_prepare(account: EmailAccount): return conn +@retry() def fetch_unseen_emails(account: EmailAccount) -> list[Email]: conn = _login_and_prepare(account) @@ -101,6 +103,7 @@ def fetch_unseen_emails(account: EmailAccount) -> list[Email]: return emails +@retry() def mark_as_seen(account: EmailAccount, uids: list[bytes]): if not uids: return diff --git a/src/retry.py b/src/retry.py new file mode 100644 index 0000000..0847b09 --- /dev/null +++ b/src/retry.py @@ -0,0 +1,29 @@ +import logging +from functools import wraps + +logger = logging.getLogger(__name__) + + +def retry(max_tries=10): + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + last_exc = None + for attempt in range(1, max_tries + 1): + try: + return func(*args, **kwargs) + except Exception as e: + last_exc = e + if attempt < max_tries: + logger.warning( + "%s 失败(第%d次),正在重试: %s", + func.__name__, attempt, e, + ) + else: + logger.error( + "%s 失败 %d 次,放弃: %s", + func.__name__, max_tries, e, + ) + raise last_exc + return wrapper + return decorator diff --git a/src/tg_bot.py b/src/tg_bot.py index 6f086f6..0846ad8 100644 --- a/src/tg_bot.py +++ b/src/tg_bot.py @@ -1,7 +1,9 @@ import requests from src.config import TelegramConfig +from src.retry import retry +@retry() def send_message(tg_cfg: TelegramConfig, text: str): url = f"https://api.telegram.org/bot{tg_cfg.bot_token}/sendMessage" payload = {