← Назад к вопросам

В какой момент агрегаторы освобождают события?

3.0 Senior🔥 92 комментариев
#Архитектура и паттерны

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как агрегаторы освобождают события в Domain-Driven Design (DDD)

В контексте Domain-Driven Design (DDD), агрегаторы освобождают (публикуют) события предметной области (domain events) в определённый момент жизненного цикла агрегата, чтобы уведомить систему о произошедших значимых изменениях. Это ключевой механизм для обеспечения реактивности, поддержания консистентности между ограниченными контекстами и реализации архитектурных стилей, таких как Event-Driven Architecture (EDA).

Ключевой момент публикации событий

Агрегаторы освобождают события непосредственно после успешного выполнения бизнес-операции внутри агрегата, но до сохранения изменений в базе данных. Точнее, это происходит в момент, когда команда (command) успешно обработана, состояние агрегата изменилось, и события сгенерированы. Однако сами события не отправляются немедленно в очередь сообщений или внешним подписчикам — они собираются и временно хранятся внутри агрегата (обычно в коллекции).

Типичный поток освобождения событий:

  1. Генерация события внутри метода агрегата при изменении состояния.
  2. Хранение события в приватном списке (например, private $events = []).
  3. Извлечение событий фреймворком или инфраструктурным слоем после успешного сохранения агрегата.
  4. Публикация событий в шину событий (event bus) или диспетчер событий.

Пример кода на PHP

<?php

class Order extends AggregateRoot
{
    private array $events = [];
    private OrderStatus $status;
    private OrderId $id;

    public function cancel(string $reason): void
    {
        // Бизнес-логика
        if ($this->status->isCancelled()) {
            throw new OrderAlreadyCancelledException();
        }
        
        $this->status = OrderStatus::cancelled();
        
        // Генерация события
        $this->recordEvent(new OrderCancelled(
            $this->id,
            $reason,
            new DateTimeImmutable()
        ));
    }
    
    private function recordEvent(DomainEvent $event): void
    {
        $this->events[] = $event;
    }
    
    public function releaseEvents(): array
    {
        $events = $this->events;
        $this->events = [];
        
        return $events;
    }
}
<?php

// Инфраструктурный слой (например, в UnitOfWork или репозитории)
class DoctrineOrderRepository implements OrderRepository
{
    public function save(Order $order): void
    {
        // 1. Сохраняем агрегат в БД
        $this->entityManager->persist($order);
        $this->entityManager->flush();
        
        // 2. Извлекаем и публикуем события
        $events = $order->releaseEvents();
        foreach ($events as $event) {
            $this->eventBus->dispatch($event);
        }
    }
}

Почему именно такая последовательность?

  1. Транзакционная целостность: События публикуются только после успешного сохранения агрегата. Если транзакция откатывается, события не будут отправлены, что предотвращает несогласованность данных.

  2. Атомарность: Изменение состояния агрегата и генерация событий происходят как единая атомарная операция. События — неотъемлемая часть изменения состояния.

  3. Изоляция агрегата: Агрегат не должен зависеть от инфраструктуры публикации событий. Он только генерирует события, а их диспетчеризацией занимается внешний механизм.

Важные нюансы реализации

  • Паттерн "Collect-and-Dispatch": Агрегат накапливает события, а инфраструктура извлекает и рассылает их после коммита транзакции.
  • Механизм извлечения: Метод releaseEvents() должен очищать внутреннюю коллекцию после извлечения, чтобы избежать повторной публикации тех же событий.
  • Обработка в рамках транзакции: В распределённых системах часто используется паттерн Transactional Outbox для гарантированной доставки событий, где события сначала сохраняются в ту же транзакцию БД, а затем фоновый процесс отправляет их в брокер сообщений.

Последствия выбора момента публикации

Если события публиковать до сохранения агрегата:

  • Риск несогласованности: события будут обработаны, но изменение агрегата может не сохраниться.
  • Нарушение атомарности.

Если события публиковать значительно позже:

  • Задержка реакции системы на изменения.
  • Потенциальные проблемы с временными метками и порядком событий.

Таким образом, оптимальный момент — сразу после успешного сохранения агрегата, что балансирует между транзакционной безопасностью и своевременностью реакций системы. Это позволяет строить отказоустойчивые, слабосвязанные системы, где различные компоненты могут реагировать на изменения предметной области без прямых зависимостей друг от друга.

В какой момент агрегаторы освобождают события? | PrepBro