Telethon客户端重启事件循环后无法捕获ConnectionError问题求助
Telethon机器人断网重启异常处理问题
问题简述
使用Telethon开发Telegram机器人,需要处理断网触发的ConnectionError,实现报错后自动重启。当前采用无限while循环启动事件循环,尝试捕获异常并停止循环以重启,但仅第一次能成功捕获异常,重启后再次触发异常会导致脚本崩溃。用ValueError测试时,该方案可多次正常捕获异常,求此差异的原因及解决方案。
原代码
import os from telethon import TelegramClient def error_catcher(loop, context): loop.stop() print('Exception catched: ', context) if __name__ == '__main__': bot = TelegramClient('test_session', api_id=os.environ['TG_API_ID'], api_hash=os.environ['TG_API_HASH']) bot.start(bot_token=os.environ['TG_BOT_TOKEN']) while True: with bot: bot.loop.set_exception_handler(error_catcher) bot.loop.run_forever()
错误日志片段
Attempt 1 at connecting failed: OSError: [Errno 101] Network is unreachable Attempt 2 at connecting failed: OSError: [Errno 101] Network is unreachable Attempt 3 at connecting failed: OSError: [Errno 101] Network is unreachable Attempt 4 at connecting failed: OSError: [Errno 101] Network is unreachable Attempt 5 at connecting failed: OSError: [Errno 101] Network is unreachable Attempt 6 at connecting failed: OSError: [Errno 101] Network is unreachable Attempt 1 at connecting failed: OSError: [Errno 101] Network is unreachable Attempt 2 at connecting failed: OSError: [Errno 101] Network is unreachable Attempt 3 at connecting failed: OSError: [Errno 101] Network is unreachable Attempt 4 at connecting failed: OSError: [Errno 101] Network is unreachable Attempt 5 at connecting failed: OSError: [Errno 101] Network is unreachable Attempt 6 at connecting failed: OSError: [Errno 101] Network is unreachable Automatic reconnection failed 5 time(s) Exception catched: {'message': 'Future exception was never retrieved', 'exception': ConnectionError('Connection to Telegram failed 5 time(s)'), 'future': <Future finished exception=ConnectionError('Connection to Telegram failed 5 time(s)')>} Attempt 1 at connecting failed: OSError: [Errno 101] Network is unreachable Attempt 2 at connecting failed: OSError: [Errno 101] Network is unreachable Attempt 3 at connecting failed: OSError: [Errno 101] Network is unreachable Attempt 4 at connecting failed: OSError: [Errno 101] Network is unreachable Attempt 5 at connecting failed: OSError: [Errno 101] Network is unreachable Attempt 6 at connecting failed: OSError: [Errno 101] Network is unreachable Traceback (most recent call last): File "/home/Sergey/PyProjects/sb/balance_bot/notification_bot.py", line 175, in <module> with bot: File "/home/Sergey/PyProjects/sb/balance_bot/venv/lib/python3.9/site-packages/telethon/helpers.py", line 219, in _sync_enter return loop.run_until_complete(self.__aenter__()) File "/usr/lib64/python3.9/asyncio/base_events.py", line 647, in run_until_complete return future.result() File "/home/Sergey/PyProjects/sb/balance_bot/venv/lib/python3.9/site-packages/telethon/client/auth.py", line 735, in __aenter__ return await self.start() File "/home/Sergey/PyProjects/sb/balance_bot/venv/lib/python3.9/site-packages/telethon/client/auth.py", line 141, in _start await self.connect() File "/home/Sergey/PyProjects/sb/balance_bot/venv/lib/python3.9/site-packages/telethon/client/telegrambaseclient.py", line 526, in connect if not await self._sender.connect(self._connection( File "/home/Sergey/PyProjects/sb/balance_bot/venv/lib/python3.9/site-packages/telethon/network/mtprotosender.py", line 128, in connect await self._connect() File "/home/Sergey/PyProjects/sb/balance_bot/venv/lib/python3.9/site-packages/telethon/network/mtprotosender.py", line 254, in _connect raise ConnectionError('Connection to Telegram failed {} time(s)'.format(self._retries)) ConnectionError: Connection to Telegram failed 5 time(s)
测试代码(可正常捕获多次异常)
import os import asyncio from telethon import TelegramClient async def stopper(): print('Started') while True: await asyncio.sleep(20) raise ValueError def error_catcher(loop, context): loop.stop() print('Exception catched: ', context) if __name__ == '__main__': bot = TelegramClient('test_session', api_id=os.environ['TG_API_ID'], api_hash=os.environ['TG_API_HASH']) bot.start(bot_token=os.environ['TG_BOT_TOKEN']) while True: with bot: bot.loop.create_task(stopper()) bot.loop.set_exception_handler(error_catcher) bot.loop.run_forever()
问题原因
- 异常触发时机差异:
- 测试代码中的
ValueError是在事件循环运行中的异步任务里抛出,此时事件循环已启动,自定义异常处理器能正常捕获并停止循环。 - 断网导致的
ConnectionError发生在with bot语句的执行阶段(即__aenter__方法内部),此时事件循环还未调用run_forever(),自定义异常处理器尚未生效,异常会直接向外层抛出,导致脚本崩溃。
- 测试代码中的
- 客户端实例状态污染:
第一次异常发生后,TelegramClient实例的内部连接状态已处于异常状态,再次进入with bot时,客户端尝试复用旧连接状态重新连接,失败后直接抛出异常,无法进入事件循环的异常处理流程。
解决方案
方案1:每次重启新建客户端与事件循环
每次循环都创建全新的TelegramClient实例和事件循环,避免旧实例的异常状态影响后续连接:
import os import asyncio from telethon import TelegramClient def error_catcher(loop, context): loop.stop() print('Exception catched: ', context) if __name__ == '__main__': while True: # 每次循环新建客户端实例 bot = TelegramClient('test_session', api_id=os.environ['TG_API_ID'], api_hash=os.environ['TG_API_HASH']) try: with bot: bot.start(bot_token=os.environ['TG_BOT_TOKEN']) bot.loop.set_exception_handler(error_catcher) bot.loop.run_forever() except ConnectionError as e: print(f"Connection failed, restarting: {e}") # 关闭旧事件循环,创建新循环避免状态残留 if not bot.loop.is_closed(): bot.loop.close() asyncio.set_event_loop(asyncio.new_event_loop())
方案2:捕获with块的连接异常
保留原客户端实例,但在外层捕获with语句执行时抛出的ConnectionError,确保循环继续:
import os from telethon import TelegramClient def error_catcher(loop, context): loop.stop() print('Exception catched: ', context) if __name__ == '__main__': bot = TelegramClient('test_session', api_id=os.environ['TG_API_ID'], api_hash=os.environ['TG_API_HASH']) bot.start(bot_token=os.environ['TG_BOT_TOKEN']) while True: try: with bot: bot.loop.set_exception_handler(error_catcher) bot.loop.run_forever() except ConnectionError as e: print(f"Connection failed, restarting: {e}") # 重置客户端连接状态 bot.disconnect()
内容的提问来源于stack exchange,提问作者Иволгин Сергей
相关产品推荐
相关产品推荐

