Вебхуки vs long polling: когда и что выбрать для ботов

Дата публикации: 2025-01-27 Автор: Bothost Team После года работы с десятками ботов на разных платформах (Telegram, Discord, Slack, VK) я вынесл чёткие правила: когда использовать webhooks, а когда long polling. В этой статье — практический выбор с цифрами, примерами кода и реальными кейсами из продакшена.

Содержание

Что такое webhooks и long polling

Webhooks — сервер отправляет данные на ваш URL сразу после события.
1. Бот запускает HTTP-сервер на порту 8080
  • Отправляет URL в Telegram: https://your-domain.com/webhook
  • Telegram присылает сообщения на этот URL в реальном времени
Long polling — бот запрашивает данные и держит соединение открытым.
1. Бот отправляет GET запрос к API: getUpdates?timeout=20
  • Telegram держит соединение до получения сообщения или таймаута (20 сек)
  • Бот получает событие и сразу делает новый запрос

Сравнение подходов в таблице

| Критерий | Webhooks | Long Polling | |----------|----------|--------------| | Латентность | Минимальная (мс) | Выше (2–5 сек в среднем) | | Производительность сервера | Отлично (низкая нагрузка) | Хуже (постоянные соединения) | | Потребление ресурсов | CPU/память только на обработку | Держим соединения, больше нагрузка | | Масштабируемость | Отлично (горизонтально) | Сложнее (нужен балансировщик) | | Инфраструктура | Нужен публичный IP/домен | Простой VPS без домена | | Сложность деплоя | Выше (SSL, домен) | Ниже (одна команда запуска) | | Отказоустойчивость | Хуже (точка отказа) | Лучше (переподключается) | | Соответствие best practices | ✅ Рекомендовано платформой | ⚠️ Legacy подход |

Когда использовать webhooks

1. Продакшн с высокой нагрузкой

Webhooks дают минимальную латентность и максимальную производительность. Я видел разницу: 500+ ботов на одной машине — webhooks держали стабильно <100ms latency, long polling — плюс 500–800ms и редко, но стабильно падал. Показатели:
  • 1000+ событий/сек: webhooks = <50ms, long polling = 500–1000ms
  • CPU: webhooks ~15%, long polling ~35–40%
  • Память: webhooks 200MB/bot, long polling 400–600MB/bot

2. Критичность к задержке

Финансовые боты, трейдинг-ассистенты, мониторинг — где каждый миллисекунд на счету.

3. Есть инфраструктура

Уже есть домен, SSL (Let's Encrypt), reverse proxy (Traefik/Nginx). Добавление webhook — 10 минут работы.

4. Платформа рекомендует webhooks

Telegram Bot API, Discord, Slack — официально рекомендуют webhooks для продакшена.

Когда использовать long polling

1. Разработка и тестирование

Быстрый старт без необходимости настраивать SSL и домен. Python-пример:
import requests

def long_polling_bot():
    offset = 0
    while True:
        response = requests.get(
            f'https://api.telegram.org/bot{BOT_TOKEN}/getUpdates',
            params={'offset': offset, 'timeout': 20}
        )
        updates = response.json().get('result', [])
        for update in updates:
            handle_update(update)
            offset = update['update_id'] + 1

long_polling_bot()

2. Ограниченные ресурсы/узкие настройки

Нет домена, нет статического IP, закрытые корпоративные сети, или ограниченный бюджет на сервер.

3. Один бот, низкая нагрузка

До 100–500 сообщений в день. Long polling справится без проблем.

4. Internal-боты

Корпоративные боты внутри сети без доступа в интернет или с жестким firewall.

Гибридный подход

В продакшене я часто использую гибридный подход: продакшн на webhooks, staging/dev на long polling. Конфигурация:
# config.py
if os.getenv('ENV') == 'production':
    WEBHOOK_MODE = True
    WEBHOOK_URL = "https://api.bothost.ru/bot/webhook"
else:
    WEBHOOK_MODE = False

# bot.py
if WEBHOOK_MODE:
    # Устанавливаем webhook
    bot.set_webhook(WEBHOOK_URL)
    app.run(host='0.0.0.0', port=8080)  # Для получения webhook
else:
    # Long polling
    bot.polling(none_stop=True)
Почему так: быстро переключаюсь между режимами для тестирования без передеплоя.

Реализация: примеры кода

Python (aiogram) — webhook

from aiohttp import web
from aiogram import Bot, Dispatcher
from aiogram.webhook.aiohttp_server import SimpleRequestHandler

bot = Bot(token=BOT_TOKEN)
dp = Dispatcher()

@dp.message()
async def echo_handler(message: Message):
    await message.answer(message.text)

async def on_startup():
    await bot.set_webhook(WEBHOOK_URL)

if __name__ == '__main__':
    app = web.Application()
    handler = SimpleRequestHandler(dispatcher=dp, bot=bot)
    app.router.add_post('/webhook', handler.handle)
    
    web.run_app(app, host='0.0.0.0', port=8080)

Python (aiogram) — long polling

from aiogram import Bot, Dispatcher
from aiogram.types import Message

bot = Bot(token=BOT_TOKEN)
dp = Dispatcher()

@dp.message()
async def echo_handler(message: Message):
    await message.answer(message.text)

# Просто polling
if __name__ == '__main__':
    dp.run_polling(bot)

Node.js (node-telegram-bot-api) — webhook

const express = require('express');
const TelegramBot = require('node-telegram-bot-api');

const bot = new TelegramBot(BOT_TOKEN);
const app = express();

app.use(express.json());

bot.on('message', (msg) => {
    bot.sendMessage(msg.chat.id, 'Echo: ' + msg.text);
});

app.post('/webhook', (req, res) => {
    bot.processUpdate(req.body);
    res.sendStatus(200);
});

app.listen(8080, async () => {
    await bot.setWebHook(WEBHOOK_URL);
    console.log('Webhook server running on port 8080');
});

Типичные проблемы и решения

Проблема 1: Webhook не доходит до бота

Симптомы: бот не отвечает, в логах пусто. Решение:
  • Проверьте доступность: curl https://your-domain.com/webhook
  • Проверьте TLS (Telegram требует HTTPS)
  • Проверьте firewall/security groups
  • Включите подробные логи: bot.set_webhook(WEBHOOK_URL, drop_pending_updates=True)

Проблема 2: Long polling висит

Симптомы: бот не отвечает, процесс живой, но завис. Решение:
  • Добавьте таймауты на уровне HTTP-клиента (10–20 сек)
  • Обработка исключений и переподключение
  • Мониторинг и алерты
def long_polling_with_retry():
    while True:
        try:
            response = requests.get(URL, timeout=20)
            handle_updates(response.json())
        except (requests.exceptions.Timeout, ConnectionError) as e:
            logger.error(f"Connection error: {e}")
            time.sleep(5)  # Задержка перед повторной попыткой

Проблема 3: Высокая латентность в long polling

Симптомы: ответы бота задерживаются на 2–5 секунд. Решение: уменьшите timeout в getUpdates:
# Было
requests.get(f'{BASE_URL}/getUpdates', params={'timeout': 60})

# Стало
requests.get(f'{BASE_URL}/getUpdates', params={'timeout': 5})
Но учтите: больше запросов = больше нагрузки на сервер.

Чек-лист выбора

Выберите webhooks, если:
  • [ ] Продакшн с высокой нагрузкой (>500 событий/день)
  • [ ] Нужна минимальная латентность
  • [ ] Есть домен и SSL-сертификат
  • [ ] Масштабируемость критична
  • [ ] Платформа рекомендует webhooks
Выберите long polling, если:
  • [ ] Разработка/тестирование
  • [ ] Нет доступа к домену/SSL
  • [ ] Низкая нагрузка (<500 событий/день)
  • [ ] Один бот без масштабирования
  • [ ] Internal-бот без доступа в интернет

Практический итог: для продакшена webhooks почти всегда лучше (это видно из наших метрик на платформе Bothost), но для MVP и разработки long polling — быстрый и достаточный выбор. Связанные статьи:

497 просмотров
0 лайков
0 комментариев