Перейти к содержимому

Доставка и эскалация

Push-уведомление доходит мгновенно — но только если телефон под рукой. Доставка (вкладка Доставка в настройках канала) решает вторую задачу: что делать, если сообщение никто не прочитал.

Для каждого канала можно включить дополнительные способы доставки. Работают они как эскалация: сообщение уходит по такому каналу, только если владелец не прочитал его за заданное время.

POST /message ──▶ push всем устройствам (мгновенно)
└─ раз в минуту: воркер доставки
├─ сообщение прочитано? → ничего не делаем
└─ прошло >= таймаута метода? → email / SMS / звонок /
Slack / Telegram / webhook
МетодЧто настраиваетсяПриходит
Emailадрес получателя, таймаутписьмо со ссылкой на сообщение и кнопками действий
СМСномер в формате +79001234567, таймауткороткий текст с названием канала и заголовком
Звонокномер, таймаутголосовой звонок с уведомлением
Slackincoming webhook URL, таймаут, мин. приоритетсообщение в канал Slack
Telegrambot token, chat ID, таймаут, мин. приоритетсообщение от бота (с inline-кнопками)
WebhookURL, необязательный секрет, таймаут, мин. приоритетPOST с JSON-телом

У каждого метода свой таймаут доставки (readTimeoutSec):

  • 0 — досылка на ближайшем прогоне воркера (то есть примерно в течение минуты);
  • 300 — если сообщение не прочитано 5 минут;
  • максимум — 23 часа (82800).

Отсчёт идёт от момента создания сообщения, а не от момента доставки push. Сообщение считается прочитанным, когда вы открыли его в админке или мобильном приложении, либо когда сработал один из endpoint-ов POST /message/read / POST /application/{id}/message/read, либо когда вы нажали кнопку ✓ Прочитано в письме или в Telegram.

В момент включения метода сервер запоминает отметку времени. Сообщения, созданные раньше этого момента, по новому методу не досылаются — иначе включение email-а вечером обернулось бы письмом обо всём, что накопилось за сутки.

У Slack, Telegram и webhook есть поле мин. приоритет: сообщения с приоритетом ниже указанного через этот адаптер не уходят. Удобно, чтобы в рабочий чат попадали только важные события, а вся мелочь оставалась в приложении.

У email, SMS и звонка фильтра по приоритету нет — они управляются только переключателем и таймаутом.

Внутри одного прогона сообщения группируются по паре «владелец + адрес»:

  • email — одно сообщение приходит обычным письмом, несколько — одним письмом-дайджестом со списком;
  • СМС — одно СМС на номер: заголовок и краткий список каналов и тем;
  • звонок — один звонок на номер, независимо от числа сообщений.

Slack, Telegram и webhook не группируются: одно сообщение — одна отправка.

МетодПоведение при сбое
email, Slack, Telegram, webhookИдемпотентны: отметка о доставке ставится после отправки, при сбое следующий прогон повторит
СМС, звонокОтметка ставится до отправки (дубль недопустим), при ошибке снимается и попытка повторяется

Каждое сообщение уходит по каждому методу ровно один раз: факт доставки фиксируется в журнале и повторно не срабатывает.

В письмо и в сообщение Telegram-бота добавляются подписанные ссылки:

  • ✓ Прочитано — отмечает сообщение прочитанным и останавливает досылку по остальным методам;
  • варианты ответа — если сообщение содержит закрытый вопрос (Ask), кнопки соответствуют вариантам ответа.

Ссылки подписаны HMAC и действуют ограниченное время (для вопросов — до истечения срока ответа), поэтому авторизация в интерфейсе для них не нужна.

Generic-webhook получает POST с JSON:

{
"title": "CPU high",
"message": "load average 12.4",
"priority": 8,
"channel": "Prod",
"appId": 12345,
"ts": 1782561600000
}

Если задан секрет, тело подписывается HMAC-SHA256 и подпись передаётся в заголовке:

X-Notifly-Signature: sha256=<hex>

Проверка на стороне получателя (Python):

import hmac, hashlib
def valid(raw_body: bytes, header: str, secret: str) -> bool:
expected = "sha256=" + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, header)

Настройки канала → вкладка Доставка. Включите нужный метод переключателем, укажите адрес и таймаут. Кнопка Проверить рядом с методом сохраняет настройки и сразу шлёт туда тестовое уведомление.

Подсказка по Telegram: создайте бота через @BotFather (/newbot) — он выдаст bot token; узнайте Chat ID (для личных сообщений — у @userinfobot, для группы это ID вида -100…); обязательно нажмите Start у своего бота или добавьте его в группу, иначе Telegram запретит отправку.

Настройки доставки — часть объекта канала, поле deliveryConfig в POST /application и PUT /application/{id}:

Окно терминала
curl -X PUT "$NOTIFLY_URL/application/12345" \
-H "Content-Type: application/json" \
-H "X-Notifly-Key: <client-token>" \
-d '{
"name": "Prod",
"deliveryConfig": {
"email": { "enabled": true, "to": "oncall@example.com", "readTimeoutSec": 300 },
"telegram": { "enabled": true, "botToken": "123:ABC", "chatId": "-1001234567890",
"readTimeoutSec": 900, "minPriority": 7 },
"webhook": { "enabled": true, "url": "https://example.com/hook",
"secret": "s3cret", "readTimeoutSec": 0, "minPriority": 5 }
}
}'

Поля адаптеров:

ПолеКто используетЗначение
enabledвсевключён ли метод
toemail, sms, callадрес или номер получателя (+79001234567)
urlslack, webhookincoming webhook URL / произвольный URL
botToken, chatIdtelegramпараметры бота
secretwebhookключ подписи HMAC-SHA256 (опционально)
readTimeoutSecвсетаймаут досылки, 082800
minPriorityslack, telegram, webhookне слать сообщения с приоритетом ниже
Окно терминала
curl -X POST "$NOTIFLY_URL/application/12345/delivery/test" \
-H "Content-Type: application/json" \
-H "X-Notifly-Key: <client-token>" \
-d '{"adapter": "telegram"}'

Без тела проверяются все включённые методы канала. Ответ — результат по каждому:

{ "results": { "telegram": { "ok": false, "error": "telegram: 403 bot was blocked by the user" } } }

Если ни один метод не включён (или указанный адаптер выключен), вернётся 400 no enabled adapter to test. Проверка идёт в обход эскалации: ждать таймаута не нужно, уведомление уходит сразу.

Досылка не расходует дневную квоту: событие уже списано при создании сообщения (message). Сколько бы методов доставки ни было включено, счётчик событий от этого не растёт — см. Квоты и тарифы.

  • URL-адреса Slack и webhook проверяются защитой от SSRF: приватные, loopback и link-local адреса на момент отправки блокируются.
  • Секреты (botToken, secret) хранятся в настройках канала и доступны только владельцу канала: получателю делегированного доступа вкладка «Доставка» недоступна.
  • Управление доставкой требует client-токена владельца канала; app-токен канала сюда не подходит.