Задать вопрос
@redmuschket

Как реализовать callback c использованием aiogram длиной более 10 секунд?

У меня по нажатию на кнопку запускается опрос AI. Ответ может формироваться минуты, а в будущем, может, часы. Прогресс-бар реализовать пока проблематично. AI предложила вариант asyncio.create_task, но это решило проблему только от части. В логи всё равно выходит
2025...  - aiogram.dispatcher - ERROR - [...] - Failed to fetch updates - TelegramNetworkError: HTTP Client says - Request timeout error
2025... - aiogram.dispatcher - WARNING - [...] - Sleep for 1.000000 seconds and try again... (tryings = 0, bot id = ...)
Раньше было всё на answer, но сейчас хочу достичь результат, чтобы у меня было одно сообщение в истории чата и файлы для пользователей, если он таковые запрашивал.
@router.callback_query(F.data.startswith("analog:"))
async def get_analog(callback: CallbackQuery, state: FSMContext):
    logger.debug("The user chose to get analogues")
    patent_id = callback.data.split(":")[1]
    tg_id = str(callback.from_user.id)

    msg = await callback.message.edit_text(" Обрабатываю ваш запрос...")

    try:
        success, token = await _auth_user.get_user_db()
        if not success:
            await callback.message.edit_text("❌ Ошибка авторизации. Попробуйте снова.")
            return
    except Exception as e:
        logger.error(f"Token error: {e}")
        await callback.message.edit_text("❌ Ошибка при проверке токена.")
        return

    await asyncio.create_task(
        process_analog_task(
            bot=callback.bot,
            chat_id=msg.chat.id,
            message_id=msg.message_id,
            patent_id=patent_id,
            access_token=access_token,
            state=state
        )
    )

async def process_analog_task(
        bot,
        chat_id: int,
        message_id: int,
        patent_id: str,
        access_token: str,
        state: FSMContext
):
    analog_service = AnalogService()
    try:
        await bot.edit_message_text(
            " Ищем аналоги... (это может занять несколько минут)",
            chat_id=chat_id,
            message_id=message_id
        )

        result = await analog_service.create_analog(patent_id, access_token)
        if result:
            await state.set_state(UserStates.analogues_received)
            await bot.edit_message_text(
                "✅ Аналоги успешно получены!",
                chat_id=chat_id,
                message_id=message_id,
                reply_markup=analog_tools(patent_id)
            )
        else:
            await bot.edit_message_text(
                "❌ Не удалось найти аналоги",
                chat_id=chat_id,
                message_id=message_id,
                reply_markup=analog_tools(patent_id))

    except Exception as e:
        logger.error(f"Error in analog processing: {e}")
        await bot.edit_message_text(
            f"❌ Ошибка",
            chat_id=chat_id,
            message_id=message_id,
            reply_markup=analog_tools(patent_id))
  • Вопрос задан
  • 302 просмотра
Подписаться 1 Простой Комментировать
Помогут разобраться в теме Все курсы
  • Академия Эдюсон
    Python-разработчик + ИИ
    9 месяцев
    Далее
  • Нетология
    1С-программист: базовый курс
    9 месяцев
    Далее
  • ProductStar × РБК
    Профессия DevOps-инженер + ИИ
    5 месяцев
    Далее
Пригласить эксперта
Ответы на вопрос 1
@dsignmark
Тут две разные проблемы, и create_task решает только первую.

1. Колбэк должен отвечать сразу. Telegram ждёт answer() на callback_query несколько секунд, поэтому порядок такой: сразу await callback.answer() (можно с текстом «Запустил, это займёт время»), отредактировать сообщение в «⏳ Обрабатываю…» и запустить работу в фоне через asyncio.create_task(...). Ссылку на задачу сохраните (например, в set), иначе сборщик мусора может её прибить.

2. Ошибки «Failed to fetch updates … Request timeout» говорят о том, что блокируется сам event loop. Скорее всего, клиент к ИИ синхронный: requests, синхронный openai-клиент или тяжёлые вычисления. Пока он работает, aiogram не может даже забрать обновления, отсюда таймауты polling. Варианты:
— асинхронный клиент (AsyncOpenAI, httpx.AsyncClient);
— или обернуть синхронный вызов: result = await asyncio.to_thread(call_ai, prompt).

Когда фоновая задача закончится, отредактируйте то же сообщение через bot.edit_message_text(chat_id=..., message_id=...) и, если нужно, отправьте файл через send_document. Так в истории останется одно сообщение и файл, как вы хотите.

Прогресс-бар делается тем же редактированием сообщения. Только не чаще раза в 2–3 секунды, иначе получите flood control.

Если задачи будут идти часами, держать их внутри процесса бота уже рискованно: перезапуск бота их потеряет. Тогда выносите работу в очередь (arq, taskiq, Celery). Бот кладёт задачу и сохраняет chat_id и message_id, воркер выполняет её и по завершении сам редактирует сообщение через Bot API.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы