Разработка и запуск обработчика
Обработчик принимает события Пачки по адресу из поля Webhook URL на вкладке Исходящий вебхук в карточке бота. Пачка отправляет их на публичный адрес http или https, а localhost и адреса внутренней сети поле не принимает, подробнее в разделе Общие настройки. Пока обработчик работает на вашей машине, события получают потоком без публичного адреса или через туннель.
Здесь — оба способа, чек-лист перед запуском в работу и что учесть в serverless. Как написать сам обработчик, описано в разделах Безопасность и обработчик и Первый бот.
Отдельный бот для разработки
У бота один Webhook URL и одна история событий. Если разрабатывать на рабочем боте, адрес вашей машины заменит адрес сервера, и события пойдут к вам. Если подключить разработку к потоку рабочего бота, на каждое событие ответят и сервер, и ваш код, а удаляя обработанные записи, вы уберёте из истории события, которые сервер забирает после сбоя.
Заведите для разработки отдельного бота с теми же событиями и правами, что у рабочего, и добавьте его в тестовый чат. Как это сделать — в разделе Создание бота.
Как получать события на своей машине
Оба способа доставляют одни и те же события. Различаются настройка бота и то, насколько код похож на рабочий.
| Что | Поток событий | Туннель |
|---|---|---|
| Публичный адрес | Не нужен | Временный адрес туннеля в Webhook URL |
| Сторонний сервис | Не нужен | ngrok, Cloudflare Tunnel или другой |
| Что включить у бота | Сохранять историю событий, адрес вебхука пустой | Исходящий вебхук с адресом туннеля |
| Права токена бота сверх рабочих | webhooks:events:read и webhooks:events:delete | bot_self:webhook:write, если адрес прописывает сам бот |
| Проверка подписи | Не нужна, доступ даёт сама ссылка | Та же, что на рабочем сервере |
| Ответ на отправку формы | Методом POSTОтвет на отправку формы | Кодом ответа на вебхук |
Потоку не нужны сторонний сервис и публичный адрес, поэтому с него проще начать. Туннель проверяет тот же код, что пойдёт на сервер, вместе с подписью и кодами ответа.
Логику бота удобно держать в функции, которая принимает payload события. В потоке payload — тот же JSON, что приходит на адрес вебхука, поэтому одна функция работает с обоими способами. Отличается ответ на отправку формы: в потоке его отправляют методом API, а на вебхук — кодом ответа, подробнее в разделе Ответ через журнал событий.
Разработка без публичного адреса
Метод GETПоток событий отдаёт ссылку, по которой события бота приходят сразу, как они происходят. Подключение к ней исходящее, поэтому публичный адрес и туннель не нужны, а на нажатие кнопки и отправку формы бот успевает ответить в срок.
Настройте бота разработки
В поток попадают те же события, что ложатся в историю, поэтому у бота разработки включите Сохранять историю событий и отметьте нужные события. Адрес вебхука оставьте пустым: тогда на отправку формы бот отвечает методом API, как в таблице выше. Вкладка Исходящий вебхук показывает настройки только вместе с адресом, поэтому боту без адреса их задают методом PUTРедактирование бота с персональным токеном, подробнее в разделе Через API. Новый бот слушает только команды, поэтому для проверки обычным сообщением выберите режим Любые сообщения, в API это all_messages.
Добавьте права токену бота
Для потока токену бота нужно право webhooks:events:read, а чтобы удалять обработанные события из истории — webhooks:events:delete. Остальные права — как у рабочего бота, подробнее в разделе Наборы прав под типовые задачи.
Посмотрите события в терминале
Получите ссылку через CLI и откройте её: события бота пойдут в терминал по мере прихода. Ссылка даёт доступ к событиям без токена, поэтому храните её как секрет.
Если команда ответила 404, у бота выключена история событий или поток недоступен.
Подключите обработчик
В коде подключайтесь к потоку в порядке, при котором события не теряются: дождитесь подтверждения подписки, дочитайте историю и меняйте ссылку до expires_at. Порядок и готовый пример на TypeScript — в разделе События в реальном времени.
Разработка с туннелем
Туннель выдаёт порту на вашей машине временный публичный адрес https. Пачка отправляет события на этот адрес, а туннель передаёт их обработчику.
Запустите обработчик
Запустите обработчик на своей машине с той же проверкой подписи и времени, что и на сервере. Примеры на TypeScript и Python — в разделе Реализация webhook handler. Команды ниже открывают туннель к порту 3000, как в примере на TypeScript. Если обработчик слушает другой порт, укажите его.
Откройте туннель
Подойдёт любой туннель с адресом https. Ниже два распространённых варианта, подробности установки — в документации ngrok и Cloudflare Tunnel.
Для ngrok нужен аккаунт ngrok и его токен из личного кабинета. Публичный адрес ngrok показывает в строке Forwarding. Бесплатный тариф даёт один постоянный адрес на домене ngrok, он не меняется между запусками, а свой домен доступен на платных тарифах.
Быстрому туннелю Cloudflare не нужны ни аккаунт, ни свой домен. Адрес вида https://….trycloudflare.com cloudflared выводит в консоль, и при каждом запуске он новый. Cloudflare предлагает быстрые туннели для тестов и разработки, а постоянный адрес на своём домене даёт именованный туннель.
Пропишите адрес туннеля боту
В Webhook URL укажите адрес туннеля с путём обработчика, например https://TUNNEL_HOST/webhook. Впишите его на вкладке Исходящий вебхук или передайте самим ботом: токеном бота с правом bot_self:webhook:write через CLI или методом PUTСаморегистрация вебхука бота. Команду удобно запускать каждый раз, когда у туннеля новый адрес.
Боту с разворачиванием ссылок адрес меняет администратор или владелец пространства, подробнее в разделе Через API.
Проверьте доставку
Отметьте нужные события на вкладке Исходящий вебхук и напишите боту в тестовом чате. Новый бот слушает только команды, поэтому для проверки обычным сообщением выберите режим Любые сообщения, подробнее в разделе Сообщения.
Пока обработчик на вашей машине остановлен, туннель сам отвечает Пачке ошибкой, а событие, на которое пришла ошибка, Пачка повторно не отправляет, подробнее в разделе Доставка и повторы. Включите у бота разработки историю событий, чтобы забрать пропущенное.
Чек-лист перед запуском в работу
Пройдите по списку, прежде чем указать в Webhook URL адрес рабочего сервера.
Безопасность
- HTTPS с действующим сертификатом. Поле принимает и
http, но по нему тело события и подпись идут открытым текстом. Пачка проверяет сертификат сервера, поэтому с самоподписанным сертификатом событие не дойдёт. Указывайте конечный адрес: по перенаправлениям Пачка не переходит, подробнее в разделе Доставка и повторы. - Проверка подписи и времени. Проверяйте подпись из заголовка
Pachca-Signatureпо сырому телу запроса сравнением за постоянное время и отклоняйте запросы со старымwebhook_timestamp. Как это сделать — в разделе Безопасность. - Белый список IP-адресов. Принимайте запросы с адресов, с которых Пачка отправляет вебхуки: список и ссылка на его актуальную версию — в разделе Безопасность. За балансировщиком или обратным прокси адрес отправителя берите из заголовка, который добавляет ваш прокси, например
X-Forwarded-For, и доверяйте этому заголовку, только когда запрос пришёл от вашего прокси. - Секреты в переменных окружения. Токен бота и Signing secret передавайте обработчику через переменные окружения или хранилище секретов, подробнее в разделе Если токен утёк. Если утёк Signing secret, удалите вебхук кнопкой Удалить вебхук и включите заново: секрет выпустится новый, а остальные настройки вкладки вернутся к начальным, подробнее в разделе Общие настройки.
Надёжность
- Быстрый ответ и очередь. Отвечайте
200сразу, а запросы к API и другую долгую работу передавайте в фоновую очередь: на ошибку или опоздание Пачка событие не повторяет. Две вещи очередь не ждут: форму поtrigger_idоткрывают в первые три секунды после нажатия, а ошибки в полях формы возвращают ответом на её отправку, тоже за три секунды. Все сроки — в разделе Сроки ответа. - Ключи идемпотентности в хранилище. Одно событие изредка приходит дважды. Храните ключи обработанных событий в базе или Redis со сроком жизни, например сутки: память процесса теряется при перезапуске и у каждого экземпляра своя. Как собрать ключ для каждого типа события — в разделе Идемпотентная обработка.
- История событий как страховка. Включите Сохранять историю событий, чтобы после простоя сервера или ответа с ошибкой забрать пропущенное методом GETИстория событий. История сама не очищается, поэтому обработанные записи удаляйте методом DELETEУдаление события истории. Токену бота для этого нужны права
webhooks:events:readиwebhooks:events:delete. Подробнее — в разделе История при работающем вебхуке.
Настройки бота
- Свои сообщения. Включите Игнорировать свои сообщения, чтобы ответ бота не запускал обработчик снова. Подробнее — в разделе Общие настройки.
- Отдельный бот. Рабочий сервер и разработка работают с разными ботами, как в разделе Отдельный бот для разработки. Так адрес вашей машины не заменит адрес сервера.
Serverless и холодный старт
Платформа serverless запускает обработчик по запросу. Первый запрос после простоя ждёт холодного старта: платформа поднимает окружение и загружает код с зависимостями, и это может занять несколько секунд.
На большинство событий запаса хватает, но два срока короткие: форму по trigger_id открывают в первые три секунды после нажатия кнопки, а на отправку формы отвечают за три секунды, подробнее в разделе Сроки ответа. Если холодный старт занял это время, форма не откроется, а при отправке формы сотрудник увидит ошибку.
- Тёплый экземпляр. Держите хотя бы один экземпляр функции запущенным: в настройках платформы это минимальное число экземпляров или зарезервированные экземпляры. Боту с формами это помогает надёжнее всего.
- Форма первым делом. В обработчике нажатия вызывайте POSTОткрытие представления сразу после проверки подписи, до остальной работы. Подключение к базе и тяжёлые модули загружайте после этого вызова.
- Работа после ответа в очереди платформы. Многие платформы приостанавливают функцию сразу после ответа, и фоновая работа в том же процессе может не завершиться. Передавайте её в очередь сообщений или в отдельную функцию.
- Ключи во внешнем хранилище. Экземпляры функции не делят память, поэтому ключи идемпотентности храните в базе или Redis.
- Вебхук вместо потока. Поток событий держит долгое подключение, а функция работает ограниченное время. В serverless принимайте события вебхуком, а поток подключайте на постоянно работающем сервере.
Если уложиться в три секунды не получается, принимайте события на постоянно работающем сервере: он сам открывает формы и отвечает на их отправку, а остальную работу передаёт в serverless через очередь.