TL;DR
При переходе на масштабы production обычная отправка email/SMS превращается в сложную распределённую систему с проблемами согласованности состояний, обработкой фейлов и race conditions. Рассмотрим архитектурные паттерны и антипаттерны на реальных примерах.
Введение: когда уведомления становятся системой
Начинающие разработчики часто воспринимают коммуникационные сервисы как простые API-вызовы:
await sendEmail(user, template); // и забыли
Но при реальных нагрузках появляются требования:
- Гарантированная доставка
- Отсутствие дублей
- Согласованность с бизнес-логикой
- Точный тайминг
- Обработка ошибок
Основная часть: проблемы и решения
1. Идемпотентность и дубли
Типичный кейс: пользователь получает 5 одинаковых SMS из-за ретраев.
Решение:
// Генерация уникального ключа для операции
const idempotencyKey = `${userId}-${eventType}-${timestamp}`;
await messagingService.send({
to: user.phone,
text: message,
idempotencyKey // Сервис гарантирует однократную обработку
});
2. Согласованность состояний
Проблема: уведомление отправлено на устаревшие данные.
Паттерн: Event Sourcing + CQRS
// Вместо прямого вызова
async function handleOrderUpdate(event: OrderEvent) {
const currentState = await orderRepo.get(event.orderId);
// Сохраняем событие
await eventStore.append(event);
// Отправляем в очередь для обработки
await queue.publish({
event,
snapshot: currentState // Опциональный снапшот
});
}
3. Тайминг и очереди
Пример конфигурации BullMQ:
const notificationQueue = new Queue('notifications', {
defaultJobOptions: {
attempts: 3,
backoff: { type: 'exponential' },
removeOnComplete: true
}
});
// Отложенная отправка
await notificationQueue.add('welcome-email',
{ userId },
{ delay: 1000 * 60 * 60 * 24 } // 24 часа
);
Практическое применение: чеклист
-
Мониторинг:
- Отслеживание задержек в очередях
- Статистика доставки по каналам
- Логирование фейлов
-
Тестирование:
- Моки сервисов в E2E-тестах
- Chaos-инжиниринг для очередей
- Проверка таймзонов
-
Архитектура:
graph LR A[Frontend] --> B[API Gateway] B --> C[Event Bus] C --> D[Notification Service] C --> E[Order Service] D --> F[Email Provider] D --> G[SMS Gateway]
Заключение
Коммуникационная инфраструктура — это отдельный слой приложения со своей сложностью. Начиная с 10k пользователей стоит задуматься о:
- Отдельном сервисе уведомлений
- Системе мониторинга
- Чётких контрактах между компонентами
Как сказал один мой коллега: “Если ваш сервис уведомлений не вызывает мигрени — вы ещё не масштабировались”.
Источник: https://www.reddit.com/r/webdev/comments/1t7uqwq/i_underestimated_how_hard_communication/