Обзор
Эта страница описывает три фоновые задачи, с которых начинается жизнь любого уведомления в Yume. Все три выполняются в отдельной очереди сообщений и решают одну и ту же задачу — записать уведомление в базу компании, — но по-разному отвечают на вопрос «а не было ли уже такого?»:Само по себе создание записи об уведомлении не занимается доставкой по каналам. Как только уведомление сохранено, автоматически при сохранении запускается веер доставки, который и рассылает его в веб, мобильный push и Telegram. Эти задачи отвечают только за то, какая именно запись появится в базе.
Общие правила для всех трёх задач
Пустой текст — выход без действий
Первое, что проверяет каждая из задач, — заполнен ли текст уведомления. Если текст пустой, задача завершается молча, ничего не создавая и не обновляя.Определение компании
Уведомление всегда принадлежит конкретной компании, и её нужно определить до любой работы с базой. Логика одинакова во всех трёх задачах и работает по приоритету:- Если задан явный ID компании (передан в задачу параметром), берётся он. Это нужно, когда задачу запускают вне контекста компании — например, из служебного кода, где текущая компания ещё не определена (контекст компании пуст).
- Иначе берётся компания из текущего подключения — но только если подключение действительно привязано к реальной компании, а не к «пустышке» без определённой компании.
- Если ни то, ни другое не дало результата, компания считается неопределённой и задача завершается молча.
Создать уведомление
Самый простой сценарий. После проверки текста и определения компании задача безусловно создаёт одну новую запись уведомления с переданными полями: тип объекта-источника и его ID, текст, доп. данные, список явных получателей, тему и набор каналов доставки. Никакой проверки на дубликаты и никакой группировки здесь нет — сколько раз задачу вызовут, столько записей и появится. Эта задача подходит для разовых, самостоятельных событий, у которых не бывает «повторов» (например, единичное системное сообщение).Обновить или создать уведомление
Задача обеспечивает ровно одно актуальное уведомление на объект-источник. Ключ дедупликации — тройка «компания + тип объекта + ID объекта». Порядок работы:- Ищутся все уведомления компании с таким же типом и ID объекта.
- Если такие уже есть — сначала удаляются все персональные записи состояния прочтения по этим уведомлениям, а затем сам текст, доп. данные и список получателей перезаписываются новыми значениями.
- Если их ещё нет — создаётся новое уведомление со всеми переданными полями, включая тему и каналы доставки.
Тема и каналы доставки применяются только при создании нового уведомления. При обновлении уже существующего они не меняются — перезаписываются лишь текст, доп. данные и список получателей.
Почему удаляется состояние прочтения
Удаление персональных записей прочтения при обновлении — намеренный приём. Смысл уведомления изменился (обновился текст), поэтому оно снова должно выглядеть непрочитанным для всех получателей. После удаления этих записей уведомление для каждого адресата снова становится «новым».Создать сгруппированное уведомление
Самый сложный сценарий. Он нужен, когда об одном и том же объекте приходит поток однотипных событий, и показывать каждое отдельным уведомлением бессмысленно. Задача сворачивает их в одну запись со счётчиком и накопленным списком последних сообщений — пока события укладываются во временное окно.Защита от гонки: кэш-блокировка
Несколько таких событий по одному объекту легко могут прийти почти одновременно и в параллельных обработчиках. Чтобы они не создали два конкурирующих уведомления, задача берёт короткую блокировку в кэше.- Ключ блокировки составляется из компании, типа объекта, ID объекта и темы — то есть блокировка индивидуальна для конкретной группы.
- Блокировка ставится на 10 секунд. Если поставить её не удалось (значит, группу прямо сейчас обрабатывает другой экземпляр), задача уходит в повтор через 1 секунду.
- Повторов допускается до 10. Вся основная работа выполняется под блокировкой, и в конце — независимо от исхода — блокировка обязательно снимается.
Поиск существующей группы (временное окно)
Под блокировкой задача вычисляет начало окна: текущий момент минус окно группировки (по умолчанию 30 минут). Затем ищется самое свежее уведомление компании с тем же типом объекта, ID объекта и темой, у которого отметка обновления не старше начала окна.Окно отсчитывается от времени последнего обновления уведомления, а не от его создания. Каждое попадание события в группу обновляет эту отметку, поэтому окно фактически скользящее: пока события приходят не реже, чем раз в 30 минут, группа продолжает жить и расти. Как только пауза превысит окно — следующее событие заведёт новую группу.
Ветка «группы ещё нет»
Если подходящей группы не нашлось, создаётся новое уведомление. В его доп. данные складываются:- счётчик событий, равный переданному шагу счётчика (по умолчанию 1);
- порция сообщений — не более последних 10 элементов.
Ветка «группа найдена» (перегруппировка)
Если группа найдена, она обновляется на месте:- Счётчик увеличивается на шаг счётчика (прежнее значение берётся из доп. данных, при отсутствии считается равным 1).
- Текст формируется одним из двух способов:
- если задан шаблон заголовка группы — текст собирается как «шаблон (счётчик)», и, если в порции есть последнее сообщение, к нему через двоеточие добавляется текст этого последнего сообщения. Например: «Новые заявки (5): заявка №123»;
- если шаблон не задан — используется базовый переданный текст как есть.
- Доп. данные пересобираются: старые данные, поверх — новые, затем обновлённый счётчик и список сообщений. Список сообщений — это прежние накопленные сообщения плюс новая порция, обрезанные до последних 10.
- Получатели заменяются новыми, только если новый список непустой; пустой список получателей прежних адресатов не затирает.
- Одноразовый захват: если событие помечено как одноразовое, у уведомления сбрасываются отметки «кем захвачено» и «время захвата», а сам флаг ставится заново.
- Удаляются все персональные записи состояния прочтения по этой группе.
- Уведомление сохраняется.
Как и при обновлении по объекту, перегруппировка удаляет состояние прочтения по группе — обновлённое уведомление снова показывается непрочитанным всем получателям.
Прямой веб-репуш после перегруппировки
После сохранения обновлённой группы (уже вне блокировки) задача дополнительно и напрямую отправляет уведомление в веб. Это нужно потому, что автоматический веер доставки полноценно срабатывает при создании, а здесь произошло обновление существующей записи. Условия и защита от дублей:- Репуш выполняется, только если среди каналов доставки уведомления есть веб.
- Он защищён отдельным ключом кэша на 30 секунд для конкретного уведомления: если за последние 30 секунд по этой группе веб-репуш уже был, повторный не отправляется. Это гасит всплеск быстрых перегруппировок.
- Список веб-получателей определяется по матрице доступа: берутся сотрудники компании с включённой подпиской на эту тему по веб-каналу. Если у уведомления задан явный список получателей, отбор дополнительно сужается только до них.
Проверка каналов при репуше опирается на каналы доставки самого уведомления, зафиксированные при его создании. Набор каналов, переданный в конкретный вызов задачи при перегруппировке, на уже существующую группу не влияет.
Как это используется
- Разовые, уникальные события ставят «Создать уведомление» — каждый вызов даёт отдельную запись.
- События, у которых важно только последнее актуальное состояние объекта (например, обновляемый статус) ставят «Обновить или создать уведомление» — на объект остаётся одна запись, и она обновляется на месте.
- Потоки однотипных событий по одному объекту (частые повторяющиеся сигналы) ставят «Создать сгруппированное уведомление» — вместо десятков записей получатель видит одну со счётчиком и списком последних сообщений.
Особенности поведения
Прочие особенности поведения:
- Все три задачи при пустом тексте уведомления завершаются молча, ничего не создавая и не логируя.
- Удаление состояния прочтения при обновлении и при перегруппировке сделано намеренно — обновлённое уведомление снова становится непрочитанным для всех получателей.
- В сгруппированном уведомлении хранятся только последние 10 сообщений — более старые вытесняются при накоплении.
- Новые получатели заменяют прежних только если список непустой; пустой список получателей не затирает уже накопленных адресатов группы.
- Прямой веб-репуш происходит только в ветке перегруппировки существующей группы; при создании новой группы задача выходит раньше и полагается на автоматический веер доставки.
- Проверка наличия веб-канала при прямом репуше опирается на каналы доставки самого сохранённого уведомления (зафиксированные при его создании), а не на набор каналов, переданный в текущий вызов при перегруппировке.
- Прямой веб-репуш защищён ключом кэша на 30 секунд на уведомление: при частых перегруппировках повторные веб-отправки в этом окне подавляются.
- Кэш-блокировка группы ставится на 10 секунд; при конфликте задача повторяется через 1 секунду, но не более 10 раз, после чего завершится ошибкой.
- Ключ группировки и блокировки включает тему, поэтому события об одном объекте, но с разными темами, образуют разные группы.
- Список веб-получателей при прямом репуше берётся из матрицы доступа (включённая подписка на тему по веб-каналу) и, если у уведомления заданы явные получатели, дополнительно сужается только до них.
Связанные страницы
Глоссарий: Создание и группировка
Полный перечень полей и терминов трёх задач создания и группировки уведомлений.
Уведомления (доставка и доступ)
Обзорная страница модуля уведомлений и всех его подразделов.
Модель и веер доставки
Модели уведомления и его персонального состояния, сигнал сохранения и разветвление доставки по каналам с учётом доступов пользователей.
Каналы доставки
Транспортные задачи и сервис доставки: веб через Ably, мобильный push через Expo с отключением мёртвых токенов и рассылка в Telegram.
Чтение, архивация и список
Адреса списка и счётчика непрочитанных, отметка прочтения и архивация, включая логику «первый забрал» и фильтры.
Push-токены устройств
Регистрация и отписка push-токенов мобильных устройств пользователя с уникальностью по устройству и типом платформы.
Привязка Telegram
Привязка и отвязка аккаунта сотрудника к Telegram-боту по одноразовому коду верификации.
Доступ и настройки
Матрица доступа «источник × тема» на пользователя, перечни источников и тем и массовое редактирование настроек уведомлений.