REPOSITORY / ScuroNeko/Laniakea

Wiki

KNOWLEDGE REPOSITORY
2
Webhook Runtime RU
ScuroNeko edited this page 2026-05-20 13:19:27 +03:00
This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Webhook Runtime RU

English version: Webhook-Runtime

Эта страница объясняет bot-level webhook runtime в Laniakea: как работает RunWebhookWithContext(...), чем он отличается от низкоуровневых webhook-вызовов в tgapi и какие runtime-гарантии он делит с polling-режимом.

Важно про naming:

  • текущий публичный API использует историческое написание WebHook в идентификаторах вроде RunWebhookWithContext(...), RunWebhook(...) и BotWebhookOpts;
  • в тексте страницы используется обычное слово "webhook", но в примерах остаются реальные имена Go API.

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

Используй webhook runtime, когда Telegram должен сам доставлять update в твой бот по HTTP вместо long polling.

Обычно это хороший вариант, если:

  • бот работает за стабильным публичным HTTPS endpoint;
  • у тебя уже есть reverse proxy или ingress;
  • ты хочешь, чтобы Telegram сам отправлял update, а бот не держал polling loop.

Используй polling, если:

  • тебе нужен самый простой локальный или маленький серверный setup;
  • ты не хочешь открывать входящий HTTP endpoint;
  • webhook-модель тебе не нужна.

Точки входа

Главные bot-level точки входа такие:

  • RunWebhookWithContext(ctx, opts, tlsFiles...)
  • RunWebhook(opts, tlsFiles...)
  • NewBotWebhookOpts()

RunWebhook(...) — это просто короткая форма для RunWebhookWithContext(context.Background(), ...).

Обычный шаблон выглядит так:

ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop()

bot, err := laniakea.NewBot[*App](opts)
if err != nil {
	return err
}
defer bot.Close()

bot.SetAppData(app)
bot.AddPlugins(plugin)

webhookOpts := laniakea.NewBotWebhookOpts().
	SetURL("https://bot.example.com").
	SetPath("/telegram").
	SetLocalPort(8080).
	SetSecretToken("shared-secret")

if err := bot.RunWebhookWithContext(ctx, webhookOpts); err != nil {
	return err
}

Что именно берет на себя bot-level runtime

RunWebhookWithContext(...) — это не просто обертка над Telegram setWebhook.

Он:

  • валидирует bot-level условия старта, например prefixes и наличие зарегистрированных plugins;
  • использует тот же single-use runtime contract, что и polling;
  • запускает runners;
  • настраивает webhook-доставку у Telegram;
  • поднимает локальный HTTP server, которым владеет сам бот;
  • принимает входящие update и отправляет их в ту же внутреннюю очередь и тот же worker pool, что используются в polling;
  • корректно завершает работу при ctx.Done().

То есть webhook mode — это часть основной runtime-модели, а не просто низкоуровневая transport setting.

Какие гарантии он делит с polling

Webhook runtime использует те же основные гарантии, что и RunWithContext(...):

  • бот остаётся single-use;
  • update проходят через внутреннюю очередь;
  • BotOpts.MaxWorkers по-прежнему управляет параллельным выполнением handlers;
  • runners стартуют на входе в runtime, а не в NewBot(...);
  • shutdown дренирует уже принятые update перед возвратом;
  • после завершения всё равно нужен Close() для освобождения локальных ресурсов.

Если ты уже понимаешь Bot-Lifecycle, то webhook mode стоит воспринимать как другой ingress path для update, а не как второй отдельный фреймворк.

Основные webhook options

BotWebhookOpts управляет и регистрацией webhook у Telegram, и локальным HTTP server.

Поля, которые важны в первую очередь:

URL

Это публичный base URL, который Telegram будет вызывать.

Если:

  • URL == "https://bot.example.com"
  • Path == "/telegram"

то в Telegram регистрируется:

  • https://bot.example.com/telegram

URL обязателен.

Path

Это локальный HTTP path, который обслуживает бот.

Используй его, чтобы не держать webhook на / и явно отделить этот маршрут в reverse proxy.

LocalPort

Это локальный порт, который слушает бот.

Типичный production-паттерн:

  • публичный TLS завершается на reverse proxy;
  • сам бот слушает внутренний HTTP-порт, например 8080.

SecretToken

Это общий секрет, который ожидается в заголовке Telegram X-Telegram-Bot-Api-Secret-Token.

Его почти всегда стоит задавать.

Без него endpoint всё равно работает, но боту приходится доверять тому, что к этому маршруту приходит только Telegram.

AllowedUpdates

Если явно вызвать SetAllowedUpdates(...), именно эти виды update будут зарегистрированы для webhook delivery.

Если оставить поле пустым, Laniakea по умолчанию возьмёт update types из bot-level конфигурации:

  • SetUpdateTypes(...)
  • AddUpdateType(...)

Это помогает не расходиться webhook-режиму с остальной конфигурацией бота.

MaxConnections

Это Telegram webhook-параметр max_connections.

Сейчас Laniakea заранее валидирует диапазон Telegram 1..100.

DropPendingUpdates

Используй это, если хочешь, чтобы Telegram отбросил уже накопившиеся update во время замены webhook.

Это deployment-решение, а не обычная runtime-настройка.

Certificate

Задай это поле, если нужно загрузить self-signed certificate в Telegram.

В этом случае бот внутри использует uploader-based регистрацию webhook.

UseStatusPath

Если включить эту опцию, бот дополнительно отдаёт /status, который возвращает текущий Telegram webhook info в виде JSON.

Для этого endpoint нужен непустой SecretToken. Если включить /status без секрета, Laniakea завершит startup ошибкой.

Это operational endpoint, а не публичный пользовательский route.

IPAddress

Используй это только тогда, когда тебе действительно нужен Telegram webhook option ip_address.

Поведение HTTP и TLS

По умолчанию RunWebhookWithContext(...) поднимает обычный HTTP server на LocalPort.

Если передать два TLS-файла, локально стартует HTTPS.

Важно:

  • текущий публичный API ожидает существующий порядок аргументов key, cert при вызове RunWebhookWithContext(...);
  • это отличается от более привычной ментальной модели cert, key, которую многие Go-разработчики ожидают от ListenAndServeTLS.

Поэтому в реальном setup лучше писать этот вызов максимально явно.

Как обрабатываются запросы

Встроенный webhook server сейчас:

  • принимает только POST;
  • при необходимости валидирует X-Telegram-Bot-Api-Secret-Token;
  • декодирует входящий Telegram Update;
  • кладёт update в обычный runtime queue бота;
  • возвращает 200 OK, когда enqueue прошёл успешно.

Если enqueue не удался из-за остановки runtime, сервер возвращает 503.

Ключевая идея в том, что webhook mode не гоняет handlers прямо внутри HTTP request. Он передаёт принятые update в ту же очередь и тот же worker pool, что используются в других runtime path.

Практика по безопасности

Минимум стоит сделать следующее:

  • задать SecretToken;
  • использовать явный Path, а не случайный /;
  • включать /status только если он реально нужен;
  • ставить бот за нормальный reverse proxy или ingress.

Также важно помнить:

  • URL — это то, что видит Telegram;
  • Path и LocalPort — это то, что реально обслуживает твой бот;
  • в production эти значения часто относятся к разным слоям инфраструктуры.
  • если ты переводишь работающий deployment с webhook-режима на polling, сначала удали webhook через CloseWebhook() или tgapi.DeleteWebhook(...); Telegram не прекращает webhook-доставку автоматически.

Связь с webhook methods в tgapi

Используй bot-level webhook runtime, когда хочешь, чтобы Laniakea сама владела:

  • регистрацией webhook;
  • локальным HTTP server;
  • приёмом update в обычную runtime queue;
  • worker-pool dispatch и shutdown semantics.

Используй более низкоуровневые вызовы tgapi, например:

  • SetWebhook(...)
  • DeleteWebhook(...)
  • GetWebhookInfo(...)
  • Uploader.SetWebhook(...)

когда тебе нужна собственная инфраструктура вокруг webhook path и ты не хочешь, чтобы сам бот владел HTTP server.

То есть:

  • RunWebhookWithContext(...) — это framework runtime API;
  • webhook methods из tgapi — это низкоуровневые transport primitives.

Частые ошибки

  • Забывать, что webhook mode тоже single-use для одного экземпляра Bot.
  • Забывать вызвать Close() после завершения runtime.
  • Переключаться с webhook mode на polling, не удалив webhook заранее.
  • Путать публичный URL с локальными Path и LocalPort.
  • Не задавать SecretToken в production-подобном deployment.
  • Предполагать привычный порядок TLS-файлов cert, key.
  • Считать /status безобидным публичным endpoint.

Связанные страницы