Коммуникационная инфраструктура: от простого уведомления до распределённой системы

#frontend#distributed-systems#event-driven

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 часа
);

Практическое применение: чеклист

  1. Мониторинг:

    • Отслеживание задержек в очередях
    • Статистика доставки по каналам
    • Логирование фейлов
  2. Тестирование:

    • Моки сервисов в E2E-тестах
    • Chaos-инжиниринг для очередей
    • Проверка таймзонов
  3. Архитектура:

    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/