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

升级aiohttp至3.8.1后,Telethon与aiohttp.server共存运行异常

解决aiohttp 3.8.1与Telethon无法同时运行的问题

我有一个同时运行Telethon机器人和aiohttp服务器的脚本,在aiohttp 3.7.4.post0版本下可正常工作,但升级到3.8.1后失效。环境为Python 3.9.6,Telethon版本未变更,预期实现Web服务器与Telegram机器人同时运行。简化代码如下:

from aiohttp import web
from telethon import TelegramClient

api_id="1234567"
api_hash="1234567890adcbefgh"
bot_token="1234567:abcdefgh0987654321"

bot=TelegramClient("my",api_id,api_hash).start(bot_token=bot_token)

# Simple TG handler
async def tg_handler(event):
    print(event.raw_text)
    await event.reply("HEY")

# Simple GET handler at /
async def http_handler_main(request):
    return web.Response(body="Hi",content_type="text/plain",charset="utf-8",status=200)

async def build_app():
    app=web.Application()
    app.add_routes([web.get("/",http_handler_main)])
    return app

bot.add_event_handler(tg_handler,events.NewMessage())
web.run_app(build_app(),port="80")

问题根源

aiohttp 3.8.x版本对web.run_app的事件循环管理做了调整,它会创建独立的事件循环并接管执行流程,而原代码中Telethon客户端是在默认事件循环中初始化启动的,两者没有共享同一个事件循环,导致Telethon的消息处理任务无法被调度执行。

解决方案

方法一:手动共享事件循环

修改代码,让Telethon和aiohttp共享同一个事件循环,通过asyncio.gather同时运行客户端任务和web服务器:

import asyncio
from aiohttp import web
from telethon import TelegramClient, events

api_id="1234567"
api_hash="1234567890adcbefgh"
bot_token="1234567:abcdefgh0987654321"

bot=TelegramClient("my", api_id, api_hash)

# Simple TG handler
async def tg_handler(event):
    print(event.raw_text)
    await event.reply("HEY")

# Simple GET handler at /
async def http_handler_main(request):
    return web.Response(body="Hi", content_type="text/plain", charset="utf-8", status=200)

async def build_app():
    app=web.Application()
    app.add_routes([web.get("/", http_handler_main)])
    return app

async def main():
    # 添加事件处理器
    bot.add_event_handler(tg_handler, events.NewMessage())
    # 启动Telethon客户端
    await bot.start(bot_token=bot_token)
    
    # 构建web应用并获取运行器
    app = await build_app()
    runner = web.AppRunner(app)
    await runner.setup()
    site = web.TCPSite(runner, port=80)
    await site.start()
    
    # 保持运行直到被中断
    await asyncio.Event().wait()

if __name__ == "__main__":
    asyncio.run(main())

方法二:利用aiohttp应用生命周期钩子

通过aiohttp的on_startup信号,在web应用启动时初始化Telethon客户端,确保两者使用同一个事件循环:

from aiohttp import web
from telethon import TelegramClient, events

api_id="1234567"
api_hash="1234567890adcbefgh"
bot_token="1234567:abcdefgh0987654321"

bot=TelegramClient("my", api_id, api_hash)

# Simple TG handler
async def tg_handler(event):
    print(event.raw_text)
    await event.reply("HEY")

# Simple GET handler at /
async def http_handler_main(request):
    return web.Response(body="Hi", content_type="text/plain", charset="utf-8", status=200)

async def start_telegram_bot(app):
    # 添加事件处理器
    bot.add_event_handler(tg_handler, events.NewMessage())
    # 启动客户端
    await bot.start(bot_token=bot_token)
    # 把客户端存入app,方便后续使用(可选)
    app["telegram_bot"] = bot

async def build_app():
    app=web.Application()
    app.add_routes([web.get("/", http_handler_main)])
    # 注册启动钩子
    app.on_startup.append(start_telegram_bot)
    return app

if __name__ == "__main__":
    web.run_app(build_app(), port=80)

关键修改说明

  • 不再直接同步调用bot.start(),而是在异步函数中等待其完成,确保客户端在当前事件循环中正确初始化
  • 方法一中通过AppRunner和TCPSite手动启动web服务,与Telethon任务共享同一个事件循环
  • 方法二中利用aiohttp的启动钩子,让Telethon客户端在web应用启动时一同初始化,自然共享事件循环

内容的提问来源于stack exchange,提问作者karurosagu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 05:21:29