Selenium. Threading. Aiogram. Ошибка: Timeout context manager should be used inside a task
Задача: в хендлере поймать команду от пользователя и запустить в отдельном потоке браузер с помощью Selenium. По мере продвижения по сайту необходимо отправить из этого же потока сообщение пользователю через await bot.send_message. Но вылетает эта ошибка. Как выйти из этого положения? Буду рад любой помощи
async def some_handler(message: types.Message)
user_id = message.from_user.id
test = Thread(target=asyncio.run, args=(save_user_profile(phone_number, user_id),))
test.start()
async def save_user_profile(phone_number, user_id):
# функция с селениумом
# какие-то действия
# зашли туда
# зашли сюда
# взяли инфу такую-то
await bot.send_message(user_id, 'какая-то инфа с сайта')
Видимо для функции await bot.send_message нет какого-то контекста, она вырвана и является чужеродной в новом потоке, сопрограмме. Что делать, товарищи? Буду рад услышать ваши умные мысли
Ответы (2 шт):
Я смог решить эту проблему. Эта ошибка появлялась, потому что в новом потоке был другой цикл событий никак не связанный с циклом событий с ботом. Поэтому я предпринял следующее:
В хендлере я получил текущий цикл событий
async def some_handler(message: types.Message)
loop = asyncio.get_event_loop() # текущий цикл событий
user_id = message.from_user.id
test = Thread(target=save_user_profile, args=(phone_number, user_id, loop, ))
test.start()
def save_user_profile(phone_number, user_id, loop):
# функция с селениумом
# какие-то действия
# зашли туда
# зашли сюда
# взяли инфу такую-то
asyncio.run_coroutine_threadsafe(bot.send_message(user_id, 'Текст'), loop)
Столкнулся со схожей проблемой, когда нужно было запустить бота и параллельно парсер. Вот, как по мне, более удобный вариант, так как функция save_user_profile остаётся асинхронной
main.py
def start_server():
"""
Starts the signals server in a separate thread
"""
def asynchronous_start(wait_for, loop: ProactorEventLoop):
# В новом потоке для asyncio устанавливаем тот же цикл
asyncio.set_event_loop(loop)
# Запускаем асинхронную функцию
loop.create_task(thread.server(wait_for))
# Достаём цикл, на котором работает бот
loop = asyncio.get_event_loop()
server_thread = threading.Thread(
target=asynchronous_start, args=(120, loop)
)
# При KeyboardInterrupt поток останавливается
server_thread.daemon = True
server_thread.start()
thread.py
async def server(wait_for: int):
user_id = ***
while True:
await asyncio.sleep(wait_for)
logger.success("Server ping")
# Избавляемся от asyncio.run_coroutine_threadsafe
await bot.send_message(user_id, 'Текст')