Как создать и развернуть вебхук для python-telegram-bot v20

Релиз v20 бота python-telegram-bot внес значительные структурные изменения. Согласно документации, Вся сетевая и вводно-выводная логика теперь работает через функции корутины (такие как async def...). В частности, все методы класса telegram.Bot, которые делают запросы к API бота, теперь являются функциями корутины и требуют...

Выпуск v20 python-telegram-bot внес большие структурные изменения. В соответствии с документацией:

«Вся логика, связанная с сетью и вводом/выводом, теперь работает через функции-корутины (т.е. функции типа async def ...). В частности, все методы класса telegram.Bot, которые делают запросы к API Bot, теперь являются функциями-корутинами и их нужно ожидать с помощью ключевого слова await» — списки изменений в python-telegram-bot v20

Процесс перехода от версии python-telegram-bot 13 до версии 20 оказался более сложным, чем я сначала ожидал. Конвертация синхронных функций def в async def и добавление await к новым корутинам было довольно простым. Но главной сложностью было найти подробную документацию о том, как «создавать и разворачивать webhooks python-telegram-bot v20 в рабочей среде».

В этой статье я объясню почему и как я сменил:

  1. python-telegram-bot v13 → v20
  2. Flask → FastAPI
  3. Gunicorn → Gunicorn + Uvicorn

Почему обновиться с v13 на v20?

v13.x и более ранние версии больше не поддерживаются командой разработчиков python-telegram-bot. Если Telegram API вводит новые функции, они будут доступны только в версии v20 и выше.

Почему использовать вебхук, а не опрос?

Большинство примеров, предоставленных командой разработчиков python-telegram-bot, используют Application.run_polling. Но вебхуки, как правило, рекомендуются перед опросом для большинства случаев использования ботов Telegram, потому что при опросе вашему боту постоянно приходится делать запросы к серверам Telegram, что может потреблять значительные ресурсы. С другой стороны, вебхуки предлагают расширенный функционал, обновляются быстрее и масштабируются лучше.

Трудности использования Flask с python-telegram-bot v20

Использование WGSI, такого как Flask, с python-telegram-bot v20 неудобно.

Flask, WSGI (Web Server Gateway Interface), синхронный и может обрабатывать только один запрос одновременно. Но вы все равно можете использовать asyncio.run() для выполнения асинхронных функций в Flask, как в примере создания пользовательского вебхук-бота, предоставленном командой разработчиков python-telegram-bot.

asyncio.run() запускает цикл событий и выполняет заданную корутину, пока она не завершится. Если перед или после обработки запроса выполняются асинхронные задачи, эти задачи будут выполняться в отдельном цикле событий.

# Код из https://docs.python-telegram-bot.org/en/v20.6/examples.customwebhookbot.htmlwebserver = uvicorn.Server(    config=uvicorn.Config(        app=WsgiToAsgi(flask_app),        port=PORT,        use_colors=False,        host="127.0.0.1",    ))async with application:  await application.start()  await webserver.serve() # запуск веб-сервера бота  await application.stop()

Однако эта реализация немного неудобна, потому что Flask несовместим с асинхронными глобальными объектами.

Примеры в документации не подходят для производственных сред.

Использование asyncio.run() в качестве точки входа в производстве обычно не рекомендуется. Функция asyncio.run() предназначена для разработки и тестирования и может не обеспечивать такой же уровень надежности и надежности, как производственные серверы, такие как Gunicorn или UWSGI.

Эти серверы предлагают множество дополнительных функций, таких как журналирование, мониторинг и проверка состояния, которые необходимы для обеспечения стабильности и безопасности производственного приложения.

Если вы хотите развернуть своего бота в продакшн, то гораздо лучше использовать ASGI (Asynchronous Server Gateway Interface) с реализацией веб-сервера ASGI.

Как это сделать – миграция и развёртывание

От Flask (WSGI) к FastAPI (AGSI)

Перенос Flask-приложения на ASGI несложен. Я выбрал FastAPI, потому что здесь я нашел подробный учебник по миграции. Синтаксис обоих фреймворков довольно похож, что означает, что вам не придется вносить слишком много изменений в код.

# От python-telegram-bot v20application = (    Application.builder()    .updater(None)    .token(<your-bot-token>) # замените <your-bot-token>    .read_timeout(7)    .get_updates_read_timeout(42)    .build())# От FastAPI@asynccontextmanagerasync def lifespan(app: FastAPI):    async with application:        await application.start()        yield        await application.stop()

Quart представляет собой вполне приемлемую альтернативу, но не предлагает поддержки для развертывания с использованием Uvicorn, который я адаптировал из скрипта, предоставленного командой python-telegram-bot.

Рабочий пример

Приведенный ниже код показывает минимальный пример использования FastAPI для создания вебхука python-telegram-bot v20. Этот бот будет отвечать “starting…” при получении команды /start.

# main.pyfrom contextlib import asynccontextmanagerfrom http import HTTPStatusfrom telegram import Updatefrom telegram.ext import Application, CommandHandlerfrom telegram.ext._contexttypes import ContextTypesfrom fastapi import FastAPI, Request, Response# Инициализация python telegram botptb = (    Application.builder()    .updater(None)    .token(<your-bot-token>) # замените <your-bot-token>    .read_timeout(7)    .get_updates_read_timeout(42)    .build())@asynccontextmanagerasync def lifespan(_: FastAPI):    await ptb.bot.setWebhook(<your-webhook-url>) # замените <your-webhook-url>    async with ptb:        await ptb.start()        yield        await ptb.stop()# Инициализация FastAPI приложения (аналог Flask)app = FastAPI(lifespan=lifespan)@app.post("/")async def process_update(request: Request):    req = await request.json()    update = Update.de_json(req, ptb.bot)    await ptb.process_update(update)    return Response(status_code=HTTPStatus.OK)# Пример обработчикаasync def start(update, _: ContextTypes.DEFAULT_TYPE):    """Send a message when the command /start is issued."""    await update.message.reply_text("starting...")ptb.add_handler(CommandHandler("start", start))

Чтобы запустить бота, установите все необходимые зависимости с помощью pip и выполните команду запуска: gunicorn main:app -k uvicorn.workers.UvicornWorker.

Этот отрывок кода адаптирован из реального Telegram-бота в продакшене. Здесь вы можете посмотреть исходный код @cron_telebot, чтобы увидеть, как он реализован. Не стесняйтесь адаптировать скрипт под свой случай использования.

Заключение

В этой статье мы узнали, как создать и развернуть вебхук python-telegram-bot v20.

Надеюсь, этот учебник вам помог. Если вам понравилась эта статья, пожалуйста, подпишитесь на меня в Medium, чтобы показать свою поддержку.

Спасибо за прочтение!


Leave a Reply

Your email address will not be published. Required fields are marked *