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

如何在同一事件循环中运行FastAPI与python-telegram-bot?

问题需求

我希望FastAPI应用能访问python-telegram-bot的实时bot_data,调用FastAPI接口时,能给bot_data里存储的所有聊天发送消息。

我清楚问题根源:bot.run_polling()和uvicorn.run(...)会启动两个独立的异步循环,必须让它们运行在同一个循环里。

更新1

感谢@MatsLindh的建议,我编写了如下函数并在main代码块中调用,但运行不稳定。有时bot.run_polling()能获取正确循环且一切正常,其他时候会因循环不一致报错:

import asyncio
from uvicorn import Config, Server
# --snip--
def run(app: FastAPI, bot:Application):
    # 使用get_event_loop会导致:
    # RuntimeError: Cannot close a running event loop
    # 推测是因为bot.run_polling()调用了loop.run_until_complete()处理不同任务
    # loop = asyncio.get_event_loop()
    loop = asyncio.new_event_loop()
    server = Server(Config(app=app, port=9001))
    loop.create_task(server.serve())

    t = Thread(target=loop.run_forever)
    t.start()

    bot.run_polling()

    t.join()
# --snip--
if __name__ == "__main__":
# --snip--
    run(f_app, bot_app)

我知道可以将bot.run_polling()拆分为多个内部独立调用,但我确信通过这个快捷函数应该可以实现需求。

初始尝试

我的简化配置如下:
最初我尝试用multiprocessing.Process而非线程运行,但bot_data始终为空——推测是进程间不共享bot数据,因此必须在同一个进程内运行。但我一直无法将所有组件运行在同一个异步循环中。

# main.py
# python3.10
# pip install fastapi[all] python-telegram-bot
from threading import Thread

import uvicorn
from telegram.ext import Application, ApplicationBuilder, PicklePersistence
from fastapi import FastAPI, Request

BOT_TOKEN = "telegram-bot-token"
MY_CHAT = 123456

class MyApp(FastAPI):
    def add_bot(self, bot_app: Application):
        self.bot_app = bot_app

async def post_init(app: Application):
    app.bot_data["key"] = 42

f_app = MyApp()

@f_app.get("/")
async def test(request: Request):
   app: MyApp = request.app
   bot_app: Application = app.bot_app
   val = bot_app.bot_data.get('key')
   print(f"{val=}")
   await bot_app.bot.send_message(MY_CHAT, f"Should be 42: {val}")


if __name__ == "__main__":
    pers = PicklePersistence("storage")
    bot_app = ApplicationBuilder().token(BOT_TOKEN).post_init(post_init).persistence(pers).build()
    f_app.add_bot(bot_app)

    t1 = Thread(target=uvicorn.run, args=(f_app,), kwargs={"port": 9001})
    t1.start()

    # --- 主线程启动轮询会导致:
    # telegram.error.NetworkError: Unknown error in HTTP implementation:
    # RuntimeError('<asyncio.locks.Event object at 0x7f2764e6fd00 [unset]> is bound to a different event loop')
    # 消息能发送且值正确,但应用崩溃返回500
    # bot_app.run_polling()

    # --- 单独线程启动轮询会导致:
    # RuntimeError: There is no current event loop in thread 'Thread-2 (run_polling)'.
    # t2 = Thread(target=bot_app.run_polling)
    # t2.start()

    # --- 用asyncio启动会导致:
    # ValueError: a coroutine was expected, got <bound method Application.run_polling ...
    # import asyncio
    # t2 = Thread(target=asyncio.run, args=(bot_app.run_polling,))
    # t2.start()

    t1.join()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 03:05:31