← все задачи

Задача 4 из 10

Сервис уведомлений

Спроектируйте сервис, который рассылает пользователям уведомления по нескольким каналам: push, email и SMS — от «заказ доставлен» до маркетинговых рассылок.

Уровень: Средний На собеседовании: 40–45 минут очереди и приоритетыретраиидемпотентность

Функциональные требования

  • Отправка уведомления по событию из других сервисов
  • Несколько каналов: push, email, SMS
  • Настройки пользователя: какие уведомления и куда слать
  • Повтор при сбое доставки

Нефункциональные требования

  • 5 млн уведомлений в сутки
  • Пик: рассылка на 1 млн получателей за 10 минут
  • Транзакционные (код подтверждения) доставляются за секунды, маркетинговые — в течение часа
  • Дубли недопустимы: пользователь не должен получить одно и то же дважды
  • Внешние провайдеры периодически недоступны или отвечают по 30 секунд

Нарисуйте архитектуру

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

Блок из палитры — добавить. Тащите мышкой или пальцем. Двойной клик по названию — переименовать. «Связь» — щёлкнуть по одному блоку, потом по другому: получится стрелка.

Схема сохраняется в этом браузере — вкладку можно закрыть и вернуться позже.

1 С чего начать, если ступор
  • Разделите приём события и доставку: приняли, положили в очередь, ответили источнику.
  • Разные очереди для транзакционных и массовых — рассылка не должна задерживать код подтверждения.
  • Дедупликация нужна по ключу события, а не по номеру попытки.
  • Ретраи с экспоненциальной задержкой и dead-letter очередь для безнадёжных.
  • Провайдер тоже лимитирует — понадобится ограничение частоты на исходящих.
2 Эталонная схема

Приняли событие — сразу в очередь и ответили источнику. Срочные и массовые разведены по разным очередям, чтобы рассылка на миллион не задерживала код подтверждения. Безнадёжные попытки уходят в dead-letter, а не крутятся вечно.

Это один из рабочих вариантов, а не единственно верный. Если у вас иначе, но вы можете объяснить почему — на собеседовании это ровно то, что нужно.

3 Разбор: что должно прозвучать

Приём и доставка разделены

  • Синхронный вызов провайдера прямо в HTTP-запросе источника — главная ошибка в этой задаче
  • API принимает событие, пишет его и кладёт в очередь; доставка живёт отдельно
  • Источнику не важно, доставлено ли уже — ему важно, что событие принято

Приоритеты

  • Отдельные очереди и отдельные воркеры для транзакционных и массовых
  • Одна общая очередь означает, что рассылка на миллион задержит код подтверждения на часы
  • Массовую рассылку имеет смысл размазывать по времени, а не вываливать разом

Идемпотентность и дубли

  • Очередь даёт at-least-once: одно и то же сообщение придёт воркеру дважды
  • Ключ дедупликации на уровне события (источник + тип + получатель + идентификатор)
  • Отметка «доставлено» должна ставиться так, чтобы повтор её увидел

Ретраи и отказы провайдера

  • Экспоненциальная задержка с джиттером: иначе все ретраи придут одной волной
  • Потолок попыток и dead-letter очередь для разбора вручную
  • Разделение ошибок: временные (повторяем) и постоянные (невалидный адрес — не повторяем)

Настройки пользователя

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

Куда копать дальше, если спросят

  • Фолбэк между каналами: push не доставлен — шлём email
  • Шаблоны, локализация и превью для маркетинга
  • Метрики доставляемости и репутация отправителя у почтовых провайдеров
  • Что делать, когда провайдер лежит час: копить в очереди или отбрасывать протухшее

Следующая задача: Лента новостей

Главный вопрос: раскладывать пост по лентам подписчиков при записи или собирать ленту при чтении. И что делать со звёздами.