Data Flow: Notifications
Жизненный цикл сообщения
-
Сборка — код приложения создаёт
NotificationPayloadDTOс получателем, темой, именем шаблона и контекстными данными. -
Рендеринг —
NotificationRendererзагружает Jinja2-шаблон, подставляет контекст и заполняет поляhtml_content/text_contentв DTO. -
Постановка в очередь — вызывается
NotificationAdapter.enqueue()с сериализованным DTO: ArqDeliveryAdapterпомещает задачу в Redis-очередь через ARQ.-
DirectDeliveryAdapterнемедленно вызывает оркестратор в текущем процессе. -
Оркестрация —
BaseDeliveryOrchestrator.deliver()перебирает зарегистрированные каналы: - Пропускает каналы, где
is_available()возвращаетFalse. - Вызывает
channel.send(to, subject, html, text). - При успехе → возвращает
True, останавливает перебор. - При исключении → логирует, переходит к следующему каналу.
-
Если все каналы исчерпаны → логирует ошибку, возвращает
False. -
Подтверждение — при доставке через ARQ воркер отмечает задачу выполненной. Для прямой доставки подтверждение не требуется.
Диаграмма последовательности
sequenceDiagram
participant App as Приложение
participant Renderer
participant Adapter
participant Queue as Redis Queue
participant Worker as ARQ Worker
participant Orchestrator
participant Channel as DeliveryChannel
App->>Renderer: render(payload_dto)
Renderer-->>App: payload_dto (с html/text)
App->>Adapter: enqueue(task_name, payload)
Adapter->>Queue: RPUSH job
Queue-->>Worker: dequeue job
Worker->>Orchestrator: deliver(payload_dto)
loop каналы по порядку
Orchestrator->>Channel: is_available()?
Orchestrator->>Channel: send(to, subject, html, text)
Channel-->>Orchestrator: True / False / Exception
end
Orchestrator-->>Worker: True (первый успех)
Пути ошибок
| Точка отказа | Поведение |
|---|---|
| Renderer бросает исключение | Проброс к вызывающему — полезная нагрузка никогда не ставится в очередь |
| Adapter бросает исключение | Проброс к вызывающему — инфраструктурная ошибка, нельзя замалчивать |
| Channel бросает исключение | Логируется, следующий канал |
| Все каналы исчерпаны | deliver() возвращает False, логируется как ошибка |