Отправить вебхук несложно: достаточно выполнить HTTP-запрос к URL получателя. Сложности начинаются, когда эта операция становится частью production-системы.
Сервер клиента может временно не отвечать. DNS или TLS-соединение может завершиться ошибкой. Приложению нужна очередь, повторные попытки — и понятный ответ на вопрос, был ли запрос в итоге доставлен. При этом повторная доставка не должна незаметно превращаться в повторную оплату, второй заказ или ещё одно уведомление.
Сегодня мы представляем Adal Outbound — отдельный контур Adal для исходящей HTTP-доставки. Приложение передаёт Adal адрес получателя, метод, заголовки и тело запроса, а Adal ставит сообщение на доставку, выполняет повторные попытки и сохраняет их результаты.
Ваше приложение → Adal Outbound → URL получателя
Outbound работает независимо от входящего потока Adal. Для него не нужно создавать Серверы Adal, Requests или Destinations: это отдельный API для приложений, которые отправляют вебхуки своим клиентам и партнёрам.
Почему одного HTTP-клиента недостаточно
В простом сценарии приложение отправляет запрос и получает 200 OK. В реальной системе между этими двумя событиями появляется много состояний:
получатель недоступен несколько секунд или минут;
соединение установлено, но ответ не пришёл до тайм-аута;
получатель вернул
429,500или другой неуспешный статус;запрос был обработан, но успешный ответ потерялся в сети;
первая попытка завершилась ошибкой DNS или TLS;
команде нужно восстановить хронологию доставки уже после инцидента.
Adal Outbound объединяет весь этот контур в одном сервисе: очередь, воркеры, планировщик retries, хранилище состояний, журнал попыток, метрики и интерфейс диагностики. Приложению достаточно передать сообщение в выбранный регион Adal — дальнейшую доставку Adal берёт на себя.
Как работает Adal Outbound
При первоначальной настройке приложение с помощью созданного в дашборде Outbound token получает access token и refresh token. Список доступных регионов достаточно запросить один раз, выбрать подходящий регион и сохранить его домен в конфигурации приложения.
После этого приложение отправляет сообщения непосредственно в выбранный регион. По мере истечения access token приложение получает новый с помощью refresh token. Список регионов отправки можно периодически обновлять отдельно — например, чтобы увидеть новые регионы или изменить географию отправки.
Для одной отправки нужно передать:
destination— обязательный публичный HTTP- или HTTPS-адрес получателя;method— обязательный HTTP-метод;headers— необязательные заголовки;body_base64— необязательное тело запроса в Base64;max_attempts— необязательное максимальное число попыток доставки.
Например:
POST https://kz2.adal.cloud/api/send
Authorization: Bearer <access-token>
Content-Type: application/json
{
"destination": "https://example.com/webhooks",
"method": "POST",
"headers": {
"Content-Type": ["application/json"],
"X-Event-Id": ["evt_01K2..."]
},
"body_base64": "eyJldmVudCI6Im9yZGVyLmNyZWF0ZWQifQ==",
"max_attempts": 3
}
В ответ Adal возвращает 202 Accepted, идентификатор сообщения, выбранный регион и начальный статус pending. Это означает, что сообщение принято и поставлено на доставку. Это ещё не означает, что получатель уже получил запрос.
После ответа 202 Accepted Adal берёт сообщение в работу, выполняет доставку и фиксирует результат каждой попытки.
Повторные попытки с предсказуемым расписанием
Доставка считается успешной, когда получатель возвращает HTTP-статус класса 2xx. Ошибка соединения, тайм-аут или любой другой HTTP-статус приводят к новой попытке, пока не будет исчерпан заданный лимит.
По умолчанию Adal выполняет до трёх попыток; для отдельного сообщения можно задать от одной до десяти. Задержка после неудачной попытки с номером N рассчитывается по простой формуле:
delay = N² minutes
После первой неудачи следующая попытка выполняется через одну минуту, после второй — через четыре, после третьей — через девять, если заданный лимит допускает ещё одну попытку. Такое расписание даёт временно недоступному сервису время на восстановление и не создаёт слишком частых повторных запросов.
Автоматические повторные попытки не расходуют дополнительные кредиты: кредиты списываются один раз, когда Adal принимает сообщение к доставке.
At-least-once и распознавание повторных попыток
Outbound использует модель at least once. В распределённой системе нельзя всегда отличить ситуацию «получатель не обработал запрос» от ситуации «получатель обработал запрос, но ответ потерялся». Поэтому при некоторых сбоях один и тот же запрос может быть доставлен больше одного раза.
Чтобы получатель мог отличить повторную попытку от нового события, в сообщение можно включить стабильный идентификатор события или idempotency key. Adal сохранит его в переданных заголовках или теле при каждой попытке доставки.
Adal оценивает результат доставки по HTTP-ответу: статус 2xx означает, что получатель успешно ответил на запрос. Бизнес-логика получателя при этом остаётся за пределами транспортного контура Adal.
История, которая помогает найти место сбоя
Для каждого сообщения в дашборде видны текущий статус и история попыток. В зависимости от результата попытки Adal показывает:
HTTP-код и заголовки ответа;
текст технической ошибки;
время DNS-разрешения;
время установления соединения и TLS;
TTFB и общее время запроса;
сведения о TLS-соединении;
цепочку redirects и итоговый URL.
Эти данные помогают отличить ошибку DNS от проблемы TLS, медленного ответа приложения или неуспешного HTTP-статуса. Вместо общего сообщения «вебхук не доставлен» команда получает хронологию конкретных попыток.
Тело HTTP-ответа получателя Adal не сохраняет и не показывает. История сообщений и попыток сейчас доступна через дашборд, а не через публичный API.
Регион выбирает отправитель
Каждое сообщение отправляется непосредственно через выбранный регион Adal. Там же сохраняются URL, метод, заголовки, тело сообщения и история доставки. Control Plane используется для аутентификации и получения списка регионов, но не служит централизованным хранилищем истории Outbound.
Явный выбор региона полезен, когда важны сетевой маршрут, география обработки или требования организации к размещению данных. При этом один лишь выбор региона не подтверждает соответствие конкретному закону или отраслевому стандарту: такую оценку организация проводит с учётом состава данных, договоров и применимых требований.
Инфраструктура Adal уже работает в нескольких странах, и мы планируем расширять географию. Актуальный список регионов приложение получает через Outbound API при первоначальной настройке и затем может обновлять независимо от отправки сообщений.
Adal не выбирает регион автоматически и не выполняет межрегиональный failover. Клиент сам определяет регион для каждой отправки. Если для проекта нужен регион, которого ещё нет в публичном списке, или отдельная инфраструктурная изоляция, напишите нам. Мы изучим требования и отдельно оценим возможную конфигурацию.
Безопасность адреса получателя
Outbound выполняет запросы по URL, который передаёт пользователь, поэтому сервис проверяет адрес назначения и защищает инфраструктуру от SSRF. Поддерживаются только публичные HTTP- и HTTPS-адреса. localhost, приватные и служебные диапазоны IP, а также URL со встроенным логином или паролем отклоняются. Адрес проверяется повторно и при HTTP redirect.
Это означает, что Outbound сейчас предназначен для доставки в публично доступные HTTP-сервисы. Для прямой отправки на 127.0.0.1, private IP или внутренний hostname он не используется.
Где пригодится Outbound
Новый контур можно использовать в любом приложении, которое отправляет HTTP-события во внешние системы. Например:
SaaS-продукт отправляет события на webhook URL клиентов;
платформа уведомляет партнёров об изменении заказа или платежа;
внутренний сервис передаёт события в публичный API CRM, help desk или другой системы;
продукт использует готовую очередь и планировщик retries Adal для своих интеграций;
команде нужна единая наблюдаемая история исходящих доставок;
для разных потоков нужно явно выбирать регион отправки и хранения истории.
Текущий поток Outbound сделан прямым и явным: один запрос к Adal создаёт одно сообщение для одного получателя, а нужный регион приложение указывает при отправке.
Начать работу
Создайте Outbound token в разделе Outbound → Tokens, получите access token и refresh token, загрузите список регионов и выберите нужный. Сохраните домен региона в конфигурации приложения и отправьте первое сообщение. После ответа 202 Accepted его состояние появится в разделе Outbound → Messages выбранного региона.
Полная схема аутентификации, формат запроса, правила retries, статусы и ограничения описаны в документации Adal Outbound.
Adal Outbound уже берёт на себя тот участок, который обычно остаётся за простым вызовом HTTP-клиента: очередь доставки, повторные попытки и данные для диагностики. Ваше приложение формирует событие и выбирает получателя. Adal делает дальнейшую доставку наблюдаемой и предсказуемой.