Skip to main content

Tag-bazlı invalidation

Cache entry’leri key bilmeden, tag üzerinden invalidate edilir. Bir spec birden çok varyant (sayfa, arama, sıralama) üretir; hepsi aynı tag altında toplandığı için tek RemoveByTagAsync(tag) çağrısı tümünü düşürür. HybridCache tag invalidation’ı lazy uygular: L2’de (Redis) tag bir timestamp ile işaretlenir; bu tag’e ait varolan entry’ler bir sonraki erişimde geçersiz sayılır. Tek tek silme (scan + DEL) yapılmaz.

CacheTags sabitleri

Spec ile domain event handler’ın aynı string’i typo’suz paylaşması için tag’ler CacheTags sınıfında merkezîleştirilir (src/.../Application/SeedWork/Caching/CacheTags.cs). Tek kaynak, tek doğruluk:
public static class CacheTags
{
    // Spec'teki sabitten türetilir — spec ve handler aynı değeri görür.
    public const string Faqs = PublicFaqsPagedSpecification.CacheTag;   // "faqs"
}
Bagis/Etkinlik aggregate’leri için cache şu an yok (anlık değişiklik görünsün diye). Public liste ölçeklenince ilgili spec’lere EnableCache + buraya tag eklenir.

Domain event handler’da invalidation

Aggregate değiştiğinde domain event yayar; ilgili handler tag’i düşürür. FAQ örneği — InvalidateFaqCacheDomainEventHandler (src/.../Application/DomainEventHandlers/FaqCreated/):
public sealed class InvalidateFaqCacheDomainEventHandler
    : INotificationHandler<FaqCreatedDomainEvent>
{
    private readonly IHybridRequestCache _cache;
    private readonly ILogger<InvalidateFaqCacheDomainEventHandler> _logger;

    public InvalidateFaqCacheDomainEventHandler(
        IHybridRequestCache cache,
        ILogger<InvalidateFaqCacheDomainEventHandler> logger)
    {
        _cache  = cache;
        _logger = logger;
    }

    public async Task Handle(FaqCreatedDomainEvent e, CancellationToken ct)
    {
        try
        {
            await _cache.RemoveByTagAsync(CacheTags.Faqs, ct);
            _logger.LogDebug("[CacheInvalidate] FaqCreated → {Tag} dropped (faqId={FaqId})", CacheTags.Faqs, e.FaqId);
        }
        catch (Exception ex)
        {
            // Cache hatası ana akışı durdurmaz: defansif try/catch + warn log.
            _logger.LogWarning(ex, "[CacheInvalidate] FaqCreated failed: faqId={FaqId}", e.FaqId);
        }
    }
}
FAQ aggregate’inin dört event’i ayrı handler dosyalarında aynı tag’i düşürür — tek tag (faqs) tüm liste varyantlarını yakalar:
Domain eventHandler diziniDüşürülen tag
FaqCreatedDomainEventDomainEventHandlers/FaqCreated/CacheTags.Faqs
FaqUpdatedDomainEventDomainEventHandlers/FaqUpdated/CacheTags.Faqs
FaqDeletedDomainEventDomainEventHandlers/FaqDeleted/CacheTags.Faqs
FaqReorderedDomainEventDomainEventHandlers/FaqReordered/CacheTags.Faqs
Invalidation domain event handler’da yapılır çünkü hangi tag’in etkilendiğini en iyi domain bilir. Yazma (Create/Update/Delete) komutu aggregate metodunu çağırır, aggregate event yayar, SaveEntitiesAsync sonrası dispatch edilir (bkz. Domain Events) ve cache handler tag’i düşürür. Komut handler cache hakkında hiçbir şey bilmez.

RemoveByTagAsync vs RemoveByTagLocallyAsync

HybridRequestCache (BuildingBlocks.Caching/HybridRequestCache.cs) iki metodu farklı amaçla taşır:
public async ValueTask RemoveByTagAsync(string tag, CancellationToken ct = default)
{
    await _cache.RemoveByTagAsync(tag, ct);   // local L1 + L2

    if (_options.CurrentValue.BroadcastTagInvalidation)
        // Diğer node'ların L1'i için broadcast (best-effort; fail olsa runtime kırılmaz).
        await _broadcaster.BroadcastInvalidationAsync(new[] { tag }, ct);
}

// Broadcast'ten geldiği için tekrar broadcast YAPMAZ — loop önleme.
public ValueTask RemoveByTagLocallyAsync(string tag, CancellationToken ct = default)
    => _cache.RemoveByTagAsync(tag, ct);
MetodLocal L1/L2BroadcastKullanım
RemoveByTagAsync✅ (config açıksa)Origin — değişikliği yapan node. Domain event handler’larda.
RemoveByTagLocallyAsyncReceiver — broadcast’i alan diğer node’lar. Cascade/loop önleme.
Receiver tarafı (CacheInvalidationIntegrationEventHandler) RemoveByTagLocallyAsync kullanır; aksi halde her node aldığı broadcast’i tekrar yayınlar ve sonsuz cascade oluşur. Ayrıntı: Multi-Instance Senkron.

İlgili

Multi-Instance Senkron

Broadcast akışı ve echo guard.

Domain Events

Event yayını ve MediatR dispatch.

Hybrid Cache

Spec cache ve IHybridRequestCache API.

Cache Mimarisi

Genel bakış.