
Привет, коллеги!
Сегодня у нас на повестке дня выбор между двумя технологиями: Polling и Webhook. Почему почему именно Webhook является go-to решением для большинства проектов?
Помните, как в начале 2010-х все разрабы активно юзали Polling? Это был золотой стандарт для многих мессенджер-ботов. Но технологии не стоят на месте. Webhook занял свое место, предлагая свои решения.
Polling
Polling, или опрос, – это процесс, при котором клиентский скрипт периодически отправляет запросы к серверу для проверки наличия новой инфы. В телеге это регулярный запрос к АПИ для получения новых обновлений или сообщений.
При увеличении нагрузки Polling может стать бутылочным горлышком. Такую проблемку можно решить увеличением интервала между запросами в моменты низкой активности и его уменьшение в пиковые часы.
Если бот обрабатывает состояния или сессии пользователей нужно учитывать, что при Polling состояние должно храниться на стороне сервера. Это означает необходимость использования БДшек и т.п
Постоянные запросы к серверу создают дополнительную нагрузку. Необходимо настраивать подходящий баланс, чтобы избежать чрезмерного трафика и потенциального блокирования вашего бота из-за слишком частых запросов. API в телеграме ожидаемо имеет ограничения на количество запросов в секунду. Необходимо убедиться, что бот не превышает эти лимиты.
Согласно документации максимальное количество сообщений, отправляемых ботом, ограничено примерно 30 сообщениями в секунду для обычных сообщений и около 20 сообщений в минуту для групповых чатов.
Если бот достигает этих лимитов, будут вылетать ошибки RetryAfter от API. Постоянные попытки повторной отправки сообщений, игнорируя ошибки API, могут привести к временной блокировке бота.
В python-telegram-bot (с версии 20), существует встроенный механизм BaseRateLimiter, который контролирует количество API запросов, совершаемых ботом за определенный временной интервал
Простейший скрипт Polling бота:
import time import requests TOKEN = "токен_бота" URL = f"https://api.telegram.org/bot{TOKEN}/getUpdates" def get_updates(): response = requests.get(URL) return response.json() def main(): while True: updates = get_updates() if updates["result"]: # Обработка каждого нового сообщения for item in updates["result"]: print(f"Сообщение от пользователя: {item['message']['text']}") time.sleep(2) # Задержка в 2 секунды между запросами if __name__ == "__main__": main()
Бот каждые две секунды спрашивает у сервера Telegram, не пришло ли новых сообщений. В реальности тут конечно должна быть обработка ошибок, логирование и другие элементы
С Polling было связано множество трудностей. Во-первых, нагрузка на сервера. Каждый бот постоянно что то запрашивал у сервера. Представьте себе тысячи ботов, делающих это каждую секунду. Это было не только неэффективно с точки зрения трафика, но и могло вызывать задержки в доставке сообщений.
Во-вторых каждый раз, когда соединение прерывалось или сервер не отвечал, это могло привести к потере апдейтов. Приходилось тщательно продумывать механизмы повторных попыток и логирования, чтобы минимизировать потери данных.
Со временем, когда телега становилась всё более попсовой, разработчики начали искать более эффективные способы взаимодействия с API. И здесь появляются вебхуки. В отличие от Polling, где бот активно запрашивал данные, Webhook позволяет серверу телеграма самому отправлять обновления боту, как только они появляются.
Webhook
Webhook – это, по сути, колллбек. Это URL, который вы предоставляете телеграму, и по которому телеграм будет отправлять обновления в формате JSON каждый раз, когда вашему боту приходит сообщение или происходит другое событие.
В начале вам нужно настроить Webhook. Это делается путем отправки запроса к Telegram API с указанием URL вашего сервера. Телега будет использовать этот URL для отправки обновлений:
from telegram.ext import Updater, CommandHandler from telegram import Bot import logging # логирование logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO) logger = logging.getLogger(__name__) # функция для обработки команды /start def start(update, context): update.message.reply_text('Привет!') def main(): TOKEN = 'token' bot = Bot(TOKEN) # Updater и передача токена вашего бота updater = Updater(token=TOKEN, use_context=True) # диспетчер для регистрации обработчиков dp = updater.dispatcher # регистрация команды /start dp.add_handler(CommandHandler("start", start)) # настроим вебхук updater.start_webhook(listen='0.0.0.0', port=8443, url_path=TOKEN, key='YOUR_PRIVATE.key', cert='YOUR_PUBLIC.pem', webhook_url='https://YOUR.SERVER.IP.ADDRESS:8443/' + TOKEN) updater.idle() if __name__ == '__main__': main()
YOUR_PRIVATE.key и YOUR_PUBLIC.pem это путь к ключу SSL, и YOUR.SERVER.IP.ADDRESS адрес сервера.
Для Webhook необходим SSL-сертификат. Telegram требует, чтобы обмен данными был защищен. Телеграм поддерживает ограниченное количество портов для Webhook: 443, 80, 88, 8443.
Для настройки SSL-терминации на веб-сервере нужно установить и настроить Nginx или Apache. На Nginx:
server { listen 443 ssl; server_name YOUR.SERVER.IP.ADDRESS; ssl_certificate /path/to/YOUR_PUBLIC.pem; ssl_certificate_key /path/to/YOUR_PRIVATE.key; location / { proxy_pass http://localhost:8443; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }
Как только кто-то взаимодействует с ботом (например, отправляет ему сообщение), телеграм делает запрос на юрл вебхук с деталями этого события. Эти данные приходят в виде JSON-объекта, который содержат информацию, к примеру:
{ "update_id": 123456789, "message": { "message_id": 111, "from": { "id": 222, "is_bot": false, "first_name": "viktor", "username": "viktor12313" }, "chat": { "id": 333, "first_name": "viktor", "username": "viktor12313", "type": "private" }, "date": 1609459200, "text": "ку" } }
Сервер затем обрабатывает этот запрос, парсит полученный JSON и выполняет необходимые действия, например, отвечает на сообщение пользователя.
Следующий шаг - это создание обработчика для входящих сообщений. В коде это обычно реализуется через определение функций с декораторами, указывающими на типы обрабатываемых сообщений (например, текст, изображения и т.д.). В качестве примера, можно использовать библиотеку fastapi вместе с telebot. Создаётся экземпляр класса AsyncTeleBot, затем настраивается webhook и определяются функции для обработки команд (/start, /help) и обычных текстовых сообщений. При получении обновления, бот использует await для асинхронной обработки сообщения и отправляет ответ:
import fastapi from telebot.async_telebot import AsyncTeleBot import telebot API_TOKEN = 'токен' WEBHOOK_URL = 'вебхук' bot = AsyncTeleBot(API_TOKEN) app = fastapi.FastAPI() @app.post('/') async def process_webhook(update: dict): if update: update = telebot.types.Update.de_json(update) await bot.process_new_updates([update]) @bot.message_handler(commands=['help', 'start']) async def send_welcome(message): await bot.reply_to(message, "Бот запущен...") @bot.message_handler(func=lambda message: True, content_types=['text']) async def echo_message(message): await bot.reply_to(message, message.text)
Итого в таблице сравнение выглядит так:
Критерий | Polling | Webhook |
|---|---|---|
Время отклика | Относительно медленное | Почти мгновенное |
Нагрузка на сервер | Высокая, требует постоянных запросов | Низкая, сервер ждёт уведомлений |
Сложность реализации | Простая, легко реализуемая | Средняя, требует настройки HTTPS, SSL |
Масштабируемость | Ограничена, увеличение нагрузки на сервер с ростом числа пользователей | Высокая, эффективна при большом количестве пользователей |
Использование ресурсов | Активное, постоянный опрос сервера | Пассивное,проще говоря принимай когда пришло |
Управление трафиком | Неэффективное, из-за постоянных запросов | Эффективное, обрабатываются только актуальные события |
Безопасность | Более уязвим для ддос атак из-за открытых запросов | Более безопасный, использует зашифрованные соединения |
Настройка и обслуживание | Простая, не требует дополнительной настройки | Сложнее, требует настройки веб-сервера и SSL-сертификата |
Webhook хоть и немного сложнее в настройке, имеет гораздо больше плюсов по сравнению с Polling.
В завершение хочу порекомендовать бесплатный урок на котором коллеги из OTUS разберут практические подходы, которые помогут вам писать чистый, поддерживаемый код на Python.
