You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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()

问题原因

  1. 异常触发时机差异:
    • 测试代码中的ValueError是在事件循环运行中的异步任务里抛出,此时事件循环已启动,自定义异常处理器能正常捕获并停止循环。
    • 断网导致的ConnectionError发生在with bot语句的执行阶段(即__aenter__方法内部),此时事件循环还未调用run_forever(),自定义异常处理器尚未生效,异常会直接向外层抛出,导致脚本崩溃。
  2. 客户端实例状态污染:
    第一次异常发生后,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,提问作者Иволгин Сергей

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 09:25:36