Короткий ответ. Надёжные уведомления через бота MAX строятся не вокруг одного вызова отправки сообщения, а вокруг полного контура: событие, запись задания, очередь, ограниченная повторная попытка, защита от дубля и журнал результата. В официальной документации MAX отправка выполняется методом POST /messages, а входящие события можно получать через Webhook, описанный в POST /subscriptions. Остальные свойства — очередность, идемпотентность и контроль бизнес-статуса — проектирует владелец интеграции.
Что именно нужно считать уведомлением
Уведомление — это сообщение, которое система отправляет человеку или рабочему чату после события в другом процессе. Событием может быть новая заявка, смена статуса заказа, завершение проверки документа, ошибка фоновой задачи или необходимость ручного решения. Важно отделить событие от сообщения: одно событие может потребовать несколько попыток доставки, а одно и то же событие не должно превращаться в несколько одинаковых уведомлений без осознанной причины.
До разработки зафиксируйте получателя, смысл сообщения, допустимую задержку и последствия пропуска. Для аварийного сигнала нужна одна стратегия, для информационного дайджеста — другая. Не смешивайте в одной очереди критические и необязательные сообщения: задержка второстепенного уведомления не должна блокировать сигнал, который требует реакции оператора.
Какие возможности MAX подтверждены документацией
Документация MAX описывает отправку сообщения через домен platform-api2.max.ru, заголовок Authorization, текст, вложения и адресата через user_id или chat_id. Метод возвращает созданное сообщение либо код ошибки. Поле notify позволяет управлять push-уведомлением для сообщения; для каналов документация отдельно оговаривает необходимость отправки с уведомлением.
Для получения обновлений MAX рекомендует продуктивный Webhook. Endpoint должен работать по HTTPS на порту 443, сертификат должен быть доверенным, а запрос следует проверить по заголовку X-Max-Bot-Api-Secret, если секрет был указан при подписке. MAX ожидает успешный ответ в течение 30 секунд; при ошибке доставки выполняет ограниченные повторные попытки. Эти правила задают транспортный контур, но не заменяют очередь внутри вашей системы.
Архитектура очереди уведомлений
Удобная модель состоит из пяти слоёв. Первый слой принимает событие и присваивает ему устойчивый идентификатор. Второй сохраняет полезную нагрузку и статус задания. Третий выбирает момент попытки. Четвёртый вызывает MAX API. Пятый записывает результат, чтобы оператор видел не только факт создания задания, но и состояние доставки в вашей системе.
| Слой | Что хранит | Проверка | Результат |
|---|---|---|---|
| Событие | Тип, источник, идентификатор | Есть обязательные поля | Принято или отклонено |
| Очередь | Адресат, текст, попытка | Дубликат ключа | Готово к отправке |
| Транспорт | Запрос и ответ MAX | HTTP-код и тело | Успех или ошибка |
| Контроль | Время, причина, оператор | Полнота журнала | Метрика и разбор |
Запись задания должна быть создана до сетевого вызова. Иначе процесс может отправить уведомление и завершиться до фиксации результата, а повтор запуска создаст второй экземпляр. На практике в очереди хранят нормализованный текст и ссылку на внутренний объект, а персональные данные в логах маскируют.
Идемпотентность и защита от дублей
MAX API принимает запрос на отправку сообщения, но в описанном методе нет обещания, что повтор того же HTTP-запроса будет распознан как тот же бизнес-операторский результат. Поэтому ключ дедупликации создаётся на вашей стороне. Например, ключом может быть комбинация тип-события + внутренний id + версия уведомления + адресат. Перед новой попыткой система проверяет этот ключ и не создаёт второй логический заказ на сообщение.
Идемпотентность нужно разделить на два уровня. На уровне очереди она не допускает двух активных заданий для одного ключа. На уровне обработчика она не даёт повторно изменить внутренний статус после успеха. Если ответ от MAX потерян, нельзя автоматически утверждать, что сообщение не создано: сначала сохраните неопределённый результат, затем примените согласованную политику проверки и ручного разбора.
Как проектировать повторы
Повтор полезен при временной ошибке, но опасен при неверном токене, удалённом адресате или ошибке данных. Разделите ошибки на временные, постоянные и неизвестные. Для временных используйте ограниченное число попыток с увеличивающимся интервалом. Для постоянных сразу переводите задание в ручной разбор. Для неизвестных сохраняйте ответ и не запускайте бесконечный цикл.
У Webhook MAX есть собственная политика повторной доставки входящих событий: документация описывает до десяти повторов с растущим интервалом и автоматическую отписку, если в течение длительного периода нет успешного ответа. Это относится к доставке событий от MAX к вашему endpoint, а не к вашей очереди исходящих уведомлений. Исходящие повторы должны иметь собственные лимиты и отдельный мониторинг.
| Ситуация | Решение | Статус |
|---|---|---|
| Временный сетевой сбой | Повтор с задержкой | retrying |
| Неверная авторизация | Остановить и уведомить владельца | blocked |
| Дубликат бизнес-ключа | Не отправлять второй раз | deduplicated |
| Исчерпан лимит | Передать в ручной разбор | dead-letter |
Формат сообщения и адресаты
Сообщение должно отвечать на четыре вопроса: что произошло, с каким объектом, когда и какое действие ожидается. Не прячьте важный контекст в длинной строке. Для рабочего чата используйте короткий заголовок, затем идентификатор объекта и ссылку на внутреннюю карточку. Ссылку формируйте из доверенного идентификатора, а не из непроверенного пользовательского ввода.
Не следует переносить в уведомление полный набор персональных данных только потому, что API позволяет отправить текст. Достаточно минимального контекста для принятия решения. Токен MAX храните в секретном хранилище и передавайте в заголовке, как указано в официальной документации. Не кладите его в HTML, клиентский код и сообщения журнала.
Мониторинг доставки
Минимальный журнал содержит ключ события, адресата, время постановки, номер попытки, HTTP-код, идентификатор сообщения при успешном ответе, причину отказа и итоговый статус. Отдельно измеряйте размер очереди, возраст самого старого задания, долю постоянных ошибок и количество ручных разборов. Не делайте вывод о доставке только по локальному факту вызова: «запрос отправлен» и «MAX вернул успешный ответ» — разные состояния.
Для Webhook проверяйте доступность HTTPS endpoint, правильность сертификата, время ответа и число ответов не 200. Если обработка события долгая, принимайте его быстро и переносите работу во внутреннюю очередь. Секрет проверяйте до разбора полезной нагрузки. Это уменьшает поверхность для поддельных запросов и упрощает расследование.
Учебный пример проектирования
Рассмотрим условный сценарий: внутренняя система создала задачу с уровнем важности «оператор». В событии есть task_id, тип изменения и идентификатор рабочего чата. Сервис сначала сохраняет ключ task-status-271-v2-chat-9, затем помещает задание в очередь. Обработчик формирует короткое сообщение, вызывает POST /messages и сохраняет ответ. Если сеть временно недоступна, статус становится retrying; если токен неверен, задание блокируется, а владелец получает отдельный сигнал.
Этот пример учебный и не является описанием реального кейса или гарантией результата. Перед запуском нужно проверить выбранный адресат, права токена, структуру запроса и ограничения конкретной версии документации MAX.
Чек-лист перед запуском
- Событие имеет устойчивый идентификатор и версию.
- Задание сохраняется до сетевого вызова.
- Есть уникальный ключ дедупликации.
- Временные и постоянные ошибки разделены.
- Повторы ограничены и попадают в ручной разбор.
- Токен хранится вне кода и логов.
- Webhook использует HTTPS, порт 443 и проверку секрета.
- В журнале есть HTTP-код и итоговый статус.
- Тест проверяет успешную отправку, тайм-аут, дубль и неверную авторизацию.
Разделение срочности и маршрутов
Даже небольшой проект выигрывает от явной матрицы срочности. Сигнал о блокирующей ошибке может идти ответственному сотруднику, обычное изменение статуса — в рабочий чат, а информационная сводка — в отложенную подборку. Такое разделение уменьшает шум и помогает выбрать разные сроки хранения и разные правила повторов. Важное сообщение не должно теряться среди десятков одинаково оформленных событий.
Для каждого маршрута зафиксируйте допустимое число попыток, максимальный возраст задания и владельца разбора. Если владелец неизвестен, задание не должно бесконечно оставаться в очереди. Система показывает его в отдельном списке, а оператор решает: повторить отправку, изменить адресата или закрыть событие как неактуальное.
Полезно хранить шаблон уведомления отдельно от события. Событие описывает факт, шаблон — способ его показать в конкретном канале. При изменении текста старые задания продолжают использовать сохранённую версию, а не внезапно получают новый формат. Это облегчает аудит и позволяет объяснить, почему оператор увидел именно такую формулировку.
Разбор инцидентов и восстановление
Если уведомления перестали уходить, сначала остановите автоматические повторы, чтобы не увеличить нагрузку и не создать дубли. Затем определите границу сбоя: события не принимаются, задания не выбираются из очереди, запросы отклоняет MAX или ответ теряется после отправки. Для каждого слоя нужны разные действия и разные доказательства.
После исправления возобновляйте отправку порциями, начиная с наиболее свежих и важных заданий. Старые информационные сообщения могут быть уже неактуальны; критические события следует проверить отдельно. Не удаляйте журнал ради «чистого» состояния: он нужен для выяснения, какие задания были отправлены, какие остались неопределёнными и какие требуют ручного решения.
Такой порядок не является функцией MAX и не гарантирует восстановление в любой аварии. Это рабочая дисциплина вашей интеграции, которую нужно проверить на тестовой копии очереди и включить в внутреннюю инструкцию.
Проверка изменений перед выпуском
Перед изменением шаблона или маршрута прогоните контрольные события в отдельной среде. Проверьте, что обязательные поля не исчезли, адресат не изменился случайно, ключ дедупликации остаётся стабильным, а новая версия шаблона не добавляет в текст секретные или лишние персональные данные. Отдельно проверьте ответ при недоступном MAX: локальная система должна сохранить понятный статус, а не считать задачу успешно отправленной.
После выпуска наблюдайте очередь и ошибки короткий период, определённый внутренним регламентом. Если растёт возраст заданий или появляются повторные сообщения, остановите конкретный маршрут и разберите несколько записей. Не меняйте сразу несколько независимых частей: иначе будет трудно установить, вызвана ли проблема текстом, адресатом, авторизацией или политикой повторов.
Проверяйте также ручной сценарий: оператор должен найти неотправленное задание, понять причину и безопасно решить, нужен ли повтор. Если такой путь отсутствует, автоматическая очередь превращается в скрытый список потерянных уведомлений.
Контроль актуальности уведомлений
Событие может устареть раньше, чем дойдёт до очереди. Поэтому при выборе задания проверяйте его срок актуальности и текущий статус объекта. Если событие уже поглощено более свежим изменением, его можно объединить или закрыть по внутреннему правилу, сохранив причину. Это снижает шум и не создаёт у оператора впечатление, что старое состояние всё ещё действует.
Правило актуальности должно быть видимым в журнале. Записывайте время события, время постановки и время отправки, а также причину пропуска. Не удаляйте устаревшие записи бесследно: для аудита достаточно минимального технического следа без лишних персональных данных.
Практический вывод
Надёжные уведомления через MAX — это управляемый процесс вокруг API, а не одиночный POST-запрос. Используйте официально описанные Webhook и метод отправки сообщений, но очередь, ключи дедупликации, классификацию ошибок и мониторинг реализуйте отдельно. Такой контур позволяет видеть, какое событие принято, что отправлено, где требуется повтор и какие сообщения нельзя повторять автоматически.