如何在一个中运行两个异步循环?

问题描述 投票:0回答:0

我希望我的 FastAPI 应用程序能够始终访问

python-telegram-bot
的实际bot_data。 我需要它,所以当我在 FastAPI 中调用某个端点时,例如,可以向所有聊天发送消息,存储在
bot_data
.

据我了解问题:

bot.run_polling()
uvicorn.run(...)
启动两个独立的异步循环。我需要将它们合二为一。

我的简化设置如下所示。

最初我尝试不使用线程而是使用

multiprocessing.Proccess
运行,但是那样我的
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()

    # --- Launching polling in main thread causes
    # telegram.error.NetworkError: Unknown error in HTTP implementation:
    # RuntimeError('<asyncio.locks.Event object at 0x7f2764e6fd00 [unset]> is bound to a different event loop')
    # message is sent and value is correct, BUT app breaks and return 500
    # bot_app.run_polling()

    # --- Launching polling in separate thread causes
    # RuntimeError: There is no current event loop in thread 'Thread-2 (run_polling)'.
    # t2 = Thread(target=bot_app.run_polling)
    # t2.start()

    # --- Launching with asyncio causes:
    # 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()
   

UPD-1:
感谢@MatsLindh,我创建了下一个传递给main块的函数,但它工作inconsistent。有时

bot.run_polling
(获得正确的循环并且一切正常,但其他时候并因错误而中断,因为存在不同的循环):

import asyncio
from uvicorn import Config, Server
# --snip--
def run(app: FastAPI, bot:Application):
    loop = asyncio.new_event_loop()
    print(f"{loop=}")
    server = Server(Config(app=app, port=9001))
    loop.create_task(server.serve())
    t = Thread(target=loop.run_forever)
    t.start()
    print(f"{loop=}")
    bot.run_polling()
    t.join()
# --snip--
if __name__ == "__main__":
# --snip--
    run(f_app, bot_app)

我也知道我可以将

bot.run_polling()
分解成几个单独的调用,这些调用在内部聚合,但我相信它应该只与那个 shortuct 函数一起工作。

asynchronous python-asyncio telegram fastapi python-telegram-bot
© www.soinside.com 2019 - 2024. All rights reserved.