如何将自定义任务集成到航标执行器中?

时间:2019-12-27 14:46:50

标签: python-asyncio telegram-bot

import asyncio
from threading import Thread
from datetime import datetime
from aiogram import Bot, Dispatcher, executor, types

API_TOKEN = ''

bot = Bot(token=API_TOKEN)
dp = Dispatcher(bot)

chat_ids = {}

@dp.message_handler()
async def echo(message: types.Message):
    # old style:
    # await bot.send_message(message.chat.id, message.text)

    chat_ids[message.message_id] = message.from_user
    text = f'{message.message_id} {message.from_user} {message.text}'
    await message.reply(text, reply=False)


async def periodic(sleep_for, queue):
    while True:
        await asyncio.sleep(sleep_for)
        now = datetime.utcnow()
        print(f"{now}")
        for id in chat_ids:
            queue.put_nowait((id, f"{now}"))
            # await bot.send_message(id, f"{now}", disable_notification=True)


def run_tick(queue):
    newloop = asyncio.new_event_loop()
    asyncio.set_event_loop(newloop)
    asyncio.run(periodic(3, queue))


if __name__ == '__main__':
    queue = asyncio.Queue()
    Thread(target=run_tick, args=(queue,), daemon=True).start()
    executor.start_polling(dp, skip_updates=True)

我想在发生事件但暂时失败时通过bot.send_message将消息发送给注册用户。 这是我尝试过的。

  1. bot.send_message崩溃,因为它是从另一个线程调用的。 (超时上下文管理器应在任务内使用)
  2. 因此,我尝试通过使用队列来解决此问题,但是无法将自己的任务添加到执行程序中。

有没有简单的方法可以做到这一点?

1 个答案:

答案 0 :(得分:0)

最初的问题是您试图从其他线程调用异步代码。为了解决由此产生的错误,您在保留附加线程的同时创建了一个新的事件循环。俗话说,现在有两个问题。

队列思想似乎还没有完成,因为没有从队列中读取的代码。即使存在,它也不起作用,因为asyncio队列没有设计为在事件循环之间或线程之间共享。为了消除混乱,您需要找到一种在事件循环内运行定期更新的方法,即重新检查以下假设:

  

但是无法将我自己的任务添加到执行程序中。

Executor的{​​{3}}看,它似乎从调度程序中拾取了事件循环,该循环将其保存在可公开访问的loop属性中。这意味着您只需在该循环上调用source方法即可创建任务。例如:

if __name__ == '__main__':
    dp.loop.create_task(periodic())
    executor.start_polling(dp, skip_updates=True)

现在periodic可以像您初次尝试时那样表述:

async def periodic(sleep_for, queue):
    while True:
        await asyncio.sleep(sleep_for)
        now = datetime.utcnow()
        for id in chat_ids:
            await bot.send_message(id, f"{now}",
                                   disable_notification=True)

请注意,由于我未使用aiogram,因此尚未进行测试。您可能需要解决的一个潜在问题是您的chat_ids字典似乎包含message.message_id作为密钥,而bot.send_message接受message.chat.id