Skip to main content

İki tür event

Sistemde iki farklı event türü vardır ve bunlar bilinçli olarak ayrı tutulur:
Domain EventIntegration Event
KapsamAynı process (in-memory)Process/servis-arası
TransportMediatR PublishIEventBus → RabbitMQ
ZamanlamaSaveChanges ile aynı transaction mantığında, commit sonrası dispatchOutbox ile aynı transaction’a yazılır, commit sonrası asenkron yayınlanır
BaseDomainEvent (SharedKernel) — INotificationIntegrationEventINotification
ÖrnekUserOtpGeneratedDomainEvent, FaqCreatedDomainEventUserCreatedIntegrationEvent, CacheInvalidationIntegrationEvent

Tam akış

Akış adım adım

  1. Command handler aggregate metodunu çağırır; aggregate AddDomainEvent(...) ile event biriktirir.
  2. UnitOfWork.SaveEntitiesAsyncbase.SaveChangesAsync (audit + soft-delete interceptor burada devrede). result > 0 ise dispatch tetiklenir.
  3. MediatorExtension.DispatchDomainEventsAsync change-tracker’daki aggregate’lerin event’lerini toplar, temizler ve tek tek dispatch eder.
  4. Event IBusEvent’ten türüyorsa (yani IntegrationEvent ise) → IEventBus.PublishAsync → Outbox tablosuna aynı DbContext transaction’ında yazılır; aksi halde mediator.Publish ile in-process INotificationHandler’lara gider.
  5. Outbox’taki satırı OutboxDeliveryService arka planda RabbitMQ’ya publish eder.
// MediatorExtension.DispatchDomainEventsAsync (özet)
foreach (var domainEvent in domainEvents)
{
    try
    {
        if (domainEvent is IBusEvent busEvent)
        {
            if (busEvent is IntegrationEvent integrationEvent)
                await ctx._eventBus.PublishAsync(integrationEvent);   // Outbox
        }
        else
        {
            await mediator.Publish(domainEvent);                       // in-process
        }
    }
    catch (Exception ex)
    {
        // Akış kesilmesin — kalan event'ler dispatch edilmeye devam etsin; ama log'lansın.
        loggerFactory?.CreateLogger(typeof(MediatorExtension))
            .LogError(ex, "[DomainEventDispatch] Event işlenemedi: {EventType}", domainEvent.GetType().Name);
    }
}
Kural: Domain event commit’le birlikte aynı mantıksal işlemde dispatch edilir; integration event commit sonrası asenkron yayınlanır. Integration event’i Outbox’a yazmak, “DB commit oldu ama mesaj yayınlanamadı” (dual-write) riskini ortadan kaldırır — ayrıntı: Outbox Pattern.
DispatchDomainEventsAsync her event’i try/catch ile sarar ve hatayı log’layıp devam eder (silent failure değil). Yani bir handler patlasa bile diğer event’ler işlenir. Kritik tutarlılık gerektiren iş için handler’ı idempotent ve dayanıklı yaz.

Hangisini ne zaman kullanmalı?

  • Domain event — aynı process içinde yan etki: OTP SMS/e-posta gönder, cache tag düşür, admin bildirimi üret.
  • Integration event — başka bir servisin (veya gelecekte ayrışacak bir bounded context’in) tüketeceği olay: welcome akışı, cross-service cache L1 senkron.

Bu bölümde

Domain Events

DomainEvent base, AddDomainEvent, INotificationHandler.

Integration Events

IntegrationEvent, IBusEvent, consumer kaydı.

Outbox Pattern

Transactional outbox, dual-write çözümü.

RabbitMQ Topology

Exchange, routing key, retry, DLX.