refactor: separate email poll, email process, TG poll into threads

- main.py spawns 3 daemon threads: email poller, email processor, TG poller
- Each thread runs independently so retries don't block other operations
- _pending_uids set + lock prevents duplicate queueing across poll cycles
- summarizer.py split into poll_accounts() (generator) and process_email()
- Graceful shutdown via shared _running flag
This commit is contained in:
2026-07-02 20:48:05 +08:00
parent 09d11a6c03
commit 1be3aadb08
2 changed files with 83 additions and 43 deletions

View File

@@ -1,43 +1,32 @@
import logging
from typing import Generator
from src.config import Config
from src.email_client import fetch_unseen_emails, mark_as_seen
from src.email_client import fetch_unseen_emails, mark_as_seen, Email
from src.ai_client import summarize_email
from src.tg_bot import send_summary, format_summary
logger = logging.getLogger(__name__)
def process_all(cfg: Config):
def poll_accounts(cfg: Config) -> Generator[tuple[int, Email], None, None]:
for idx, acct in enumerate(cfg.email_accounts):
try:
_process_account(cfg, acct, idx)
logger.info(f"检查邮箱: {acct.username}")
emails = fetch_unseen_emails(acct)
if emails:
logger.info(f" 发现 {len(emails)} 封新邮件")
for mail in emails:
yield idx, mail
except Exception as e:
logger.error(f"处理邮箱 {acct.username} 时出错: {e}", exc_info=True)
logger.error(f"轮询 {acct.username} 失败: {e}", exc_info=True)
def _process_account(cfg: Config, acct, acct_idx: int):
logger.info(f"检查邮箱: {acct.username}")
emails = fetch_unseen_emails(acct)
if not emails:
logger.info(f" 没有新邮件")
return
logger.info(f" 发现 {len(emails)} 封新邮件")
seen_uids = []
for mail in emails:
try:
logger.info(f" 正在摘要: {mail.subject}")
summary = summarize_email(cfg.ai, acct.username, mail.subject, mail.sender, mail.body)
summary["recipient"] = acct.username
text = format_summary(summary)
send_summary(cfg.telegram, cfg.telegram.chat_id, text, summary, mail.body, acct_idx)
seen_uids.append(mail.uid)
logger.info(f" 已发送到 Telegram")
except Exception as e:
logger.error(f" 处理邮件 '{mail.subject}' 失败: {e}", exc_info=True)
seen_uids.append(mail.uid)
if seen_uids:
mark_as_seen(acct, seen_uids)
def process_email(cfg: Config, acct_idx: int, mail: Email):
acct = cfg.email_accounts[acct_idx]
logger.info(f" 正在摘要: {mail.subject}")
summary = summarize_email(cfg.ai, acct.username, mail.subject, mail.sender, mail.body)
summary["recipient"] = acct.username
text = format_summary(summary)
send_summary(cfg.telegram, cfg.telegram.chat_id, text, summary, mail.body, acct_idx)
mark_as_seen(acct, [mail.uid])
logger.info(f" 已处理: {mail.subject}")