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将消息发送给注册用户。 这是我尝试过的。
有没有简单的方法可以做到这一点?
答案 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
。