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 шт):

Автор решения: VlasssaDassa

Я смог решить эту проблему. Эта ошибка появлялась, потому что в новом потоке был другой цикл событий никак не связанный с циклом событий с ботом. Поэтому я предпринял следующее:

В хендлере я получил текущий цикл событий

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)
→ Ссылка
Автор решения: Radikulit

Столкнулся со схожей проблемой, когда нужно было запустить бота и параллельно парсер. Вот, как по мне, более удобный вариант, так как функция 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, 'Текст')
→ Ссылка