Для разработчиков

Разработка и запуск обработчика

Обработчик принимает события Пачки по адресу из поля Webhook URL на вкладке Исходящий вебхук в карточке бота. Пачка отправляет их на публичный адрес http или https, а localhost и адреса внутренней сети поле не принимает, подробнее в разделе Общие настройки. Пока обработчик работает на вашей машине, события получают потоком без публичного адреса или через туннель.

Здесь — оба способа, чек-лист перед запуском в работу и что учесть в serverless. Как написать сам обработчик, описано в разделах Безопасность и обработчик и Первый бот.

Отдельный бот для разработки

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

Заведите для разработки отдельного бота с теми же событиями и правами, что у рабочего, и добавьте его в тестовый чат. Как это сделать — в разделе Создание бота.

Как получать события на своей машине

Оба способа доставляют одни и те же события. Различаются настройка бота и то, насколько код похож на рабочий.

ЧтоПоток событийТуннель
Публичный адресНе нуженВременный адрес туннеля в Webhook URL
Сторонний сервисНе нуженngrok, Cloudflare Tunnel или другой
Что включить у ботаСохранять историю событий, адрес вебхука пустойИсходящий вебхук с адресом туннеля
Права токена бота сверх рабочихwebhooks:events:read и webhooks:events:deletebot_self:webhook:write, если адрес прописывает сам бот
Проверка подписиНе нужна, доступ даёт сама ссылкаТа же, что на рабочем сервере
Ответ на отправку формыМетодом POSTОтвет на отправку формыКодом ответа на вебхук

Потоку не нужны сторонний сервис и публичный адрес, поэтому с него проще начать. Туннель проверяет тот же код, что пойдёт на сервер, вместе с подписью и кодами ответа.

Логику бота удобно держать в функции, которая принимает payload события. В потоке payload — тот же JSON, что приходит на адрес вебхука, поэтому одна функция работает с обоими способами. Отличается ответ на отправку формы: в потоке его отправляют методом API, а на вебхук — кодом ответа, подробнее в разделе Ответ через журнал событий.

Разработка без публичного адреса

Метод GETПоток событий отдаёт ссылку, по которой события бота приходят сразу, как они происходят. Подключение к ней исходящее, поэтому публичный адрес и туннель не нужны, а на нажатие кнопки и отправку формы бот успевает ответить в срок.

Настройте бота разработки

В поток попадают те же события, что ложатся в историю, поэтому у бота разработки включите Сохранять историю событий и отметьте нужные события. Адрес вебхука оставьте пустым: тогда на отправку формы бот отвечает методом API, как в таблице выше. Вкладка Исходящий вебхук показывает настройки только вместе с адресом, поэтому боту без адреса их задают методом PUTРедактирование бота с персональным токеном, подробнее в разделе Через API. Новый бот слушает только команды, поэтому для проверки обычным сообщением выберите режим Любые сообщения, в API это all_messages.

# 1738816 — id бота разработки, команда работает с персональным токеномpachca bots update 1738816 --events-history-enabled --trigger-on all_messages \  --events '["message_new","button_click"]'

Добавьте права токену бота

Для потока токену бота нужно право webhooks:events:read, а чтобы удалять обработанные события из истории — webhooks:events:delete. Остальные права — как у рабочего бота, подробнее в разделе Наборы прав под типовые задачи.

Посмотрите события в терминале

Получите ссылку через CLI и откройте её: события бота пойдут в терминал по мере прихода. Ссылка даёт доступ к событиям без токена, поэтому храните её как секрет.

# PACHCA_BOT_TOKEN — токен бота разработкиSTREAM_URL=$(PACHCA_TOKEN=$PACHCA_BOT_TOKEN pachca bots get-stream -o json | jq -r '.url')curl -N "$STREAM_URL"

Если команда ответила 404, у бота выключена история событий или поток недоступен.

Подключите обработчик

В коде подключайтесь к потоку в порядке, при котором события не теряются: дождитесь подтверждения подписки, дочитайте историю и меняйте ссылку до expires_at. Порядок и готовый пример на TypeScript — в разделе События в реальном времени.

Разработка с туннелем

Туннель выдаёт порту на вашей машине временный публичный адрес https. Пачка отправляет события на этот адрес, а туннель передаёт их обработчику.

Запустите обработчик

Запустите обработчик на своей машине с той же проверкой подписи и времени, что и на сервере. Примеры на TypeScript и Python — в разделе Реализация webhook handler. Команды ниже открывают туннель к порту 3000, как в примере на TypeScript. Если обработчик слушает другой порт, укажите его.

Откройте туннель

Подойдёт любой туннель с адресом https. Ниже два распространённых варианта, подробности установки — в документации ngrok и Cloudflare Tunnel.

Для ngrok нужен аккаунт ngrok и его токен из личного кабинета. Публичный адрес ngrok показывает в строке Forwarding. Бесплатный тариф даёт один постоянный адрес на домене ngrok, он не меняется между запусками, а свой домен доступен на платных тарифах.

brew install ngrok    # macOS, другие системы — в документации ngrokngrok config add-authtoken YOUR_NGROK_TOKENngrok http 3000

Быстрому туннелю Cloudflare не нужны ни аккаунт, ни свой домен. Адрес вида https://….trycloudflare.com cloudflared выводит в консоль, и при каждом запуске он новый. Cloudflare предлагает быстрые туннели для тестов и разработки, а постоянный адрес на своём домене даёт именованный туннель.

brew install cloudflared    # macOS, другие системы — в документации Cloudflarecloudflared tunnel --url http://localhost:3000

Пропишите адрес туннеля боту

В Webhook URL укажите адрес туннеля с путём обработчика, например https://TUNNEL_HOST/webhook. Впишите его на вкладке Исходящий вебхук или передайте самим ботом: токеном бота с правом bot_self:webhook:write через CLI или методом PUTСаморегистрация вебхука бота. Команду удобно запускать каждый раз, когда у туннеля новый адрес.

PACHCA_TOKEN=$PACHCA_BOT_TOKEN pachca bots update-webhook --outgoing-url https://TUNNEL_HOST/webhook
curl -X PUT https://api.pachca.com/api/shared/v1/bot/webhook \  -H "Authorization: Bearer $PACHCA_BOT_TOKEN" \  -H "Content-Type: application/json" \  -d '{"webhook": {"outgoing_url": "https://TUNNEL_HOST/webhook"}}'

Боту с разворачиванием ссылок адрес меняет администратор или владелец пространства, подробнее в разделе Через API.

Проверьте доставку

Отметьте нужные события на вкладке Исходящий вебхук и напишите боту в тестовом чате. Новый бот слушает только команды, поэтому для проверки обычным сообщением выберите режим Любые сообщения, подробнее в разделе Сообщения.

Пока обработчик на вашей машине остановлен, туннель сам отвечает Пачке ошибкой, а событие, на которое пришла ошибка, Пачка повторно не отправляет, подробнее в разделе Доставка и повторы. Включите у бота разработки историю событий, чтобы забрать пропущенное.

Запросы приходят к обработчику с адреса туннеля, поэтому на своей машине проверку IP-адреса отключите. Подпись и время проверяйте как обычно.

Чек-лист перед запуском в работу

Пройдите по списку, прежде чем указать в 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 через очередь.