import asyncio import sys from datetime import datetime, timedelta from loguru import logger from core.config import Config from core.database import DatabaseManager from core.logger import setup_logger class RetryingAccountsReset: def __init__(self): self.config = Config.from_yaml() self.logger = setup_logger(self.config) self.db_manager = DatabaseManager(self.config) async def initialize(self): """初始化数据库""" await self.db_manager.initialize() async def cleanup(self): """清理资源""" await self.db_manager.cleanup() async def reset_stuck_accounts(self, timeout_minutes=30): """重置卡在retrying状态的账号""" try: # 计算超时时间 timeout_time = datetime.now() - timedelta(minutes=timeout_minutes) timeout_str = timeout_time.strftime('%Y-%m-%d %H:%M:%S') self.logger.info(f"开始重置超时的retrying账号 (超过{timeout_minutes}分钟)") async with self.db_manager.get_connection() as conn: # 查询当前处于retrying状态的账号数量 cursor = await conn.execute( "SELECT COUNT(*) FROM email_accounts WHERE status = 'retrying'" ) count = (await cursor.fetchone())[0] if count == 0: self.logger.info("没有找到处于retrying状态的账号") return 0 # 更新超时的retrying账号为failed状态 cursor = await conn.execute( """ UPDATE email_accounts SET status = 'failed', updated_at = CURRENT_TIMESTAMP WHERE status = 'retrying' AND updated_at < ? RETURNING id, email """, (timeout_str,) ) # 获取被重置的账号信息 reset_accounts = await cursor.fetchall() await conn.commit() reset_count = len(reset_accounts) # 打印重置的账号列表 if reset_count > 0: self.logger.info(f"已重置 {reset_count} 个账号状态从retrying到failed:") for account in reset_accounts: self.logger.debug(f"ID: {account[0]}, 邮箱: {account[1]}") else: self.logger.info(f"没有找到超过{timeout_minutes}分钟的retrying账号") return reset_count except Exception as e: self.logger.error(f"重置retrying账号失败: {str(e)}") return 0 async def main(): # 解析命令行参数 timeout_minutes = 30 # 默认超时时间30分钟 if len(sys.argv) > 1: try: timeout_minutes = int(sys.argv[1]) except ValueError: print(f"参数错误: 超时时间必须是整数,将使用默认值 {timeout_minutes}分钟") # 初始化 reset = RetryingAccountsReset() await reset.initialize() try: # 执行重置 await reset.reset_stuck_accounts(timeout_minutes) except Exception as e: logger.error(f"程序执行出错: {str(e)}") finally: await reset.cleanup() if __name__ == "__main__": asyncio.run(main())