TGViewer
C# Geeks (.NET) C# Geeks (.NET) @csharpgeeks · 550 subscribers
Post #587 227
پیاده‌سازی راه‌حل ⚙️

ما به کتابخانه‌ی StackExchange.Redis برای مدیریت پیام‌رسانی نیاز داریم.

بیایید با تعریف یک سرویس ساده برای انتشار (publishing) شروع کنیم. این سرویس مسئول اطلاع دادن به بقیه‌ی سیستم است که یک کلید تغییر کرده است. 🔔
public interface ICacheInvalidator
{
Task InvalidateAsync(string key, CancellationToken cancellationToken = default);
}

public class RedisCacheInvalidator(
IConnectionMultiplexer connectionMultiplexer,
ILogger<RedisCacheInvalidator> logger)
: ICacheInvalidator
{
private const RedisChannel Channel = RedisChannel.Literal("cache-invalidation");

public async Task InvalidateAsync(string key, CancellationToken cancellationToken = default)
{
var subscriber = connectionMultiplexer.GetSubscriber();

await subscriber.PublishAsync(Channel, new RedisValue(key));

logger.LogInformation("Published invalidation for key: {Key}", key);
}
}

حالا هر زمان که یک entity را در Command Handler یا Service آپدیت می‌کنید، کافی است متد ICacheInvalidator.InvalidateAsync را صدا بزنید. 🚀
public class UpdateUserProfileHandler(
AppDbContext dbContext,
ICacheInvalidator cacheInvalidator,
ILogger<UpdateUserProfileHandler> logger)
{
public async Task Handle(int userId, string newName, CancellationToken ct)
{
// 1. Update the database
var user = await dbContext.Users.FindAsync([userId], ct);
if (user is null)
{
return;
}

user.Name = newName;
await dbContext.SaveChangesAsync(ct);

// 2. Invalidate the cache (Distributed)
var cacheKey = $"user:{userId}";
await cacheInvalidator.InvalidateAsync(cacheKey, ct);

logger.LogInformation("Updated user and invalidated cache for {UserId}", userId);
}
}


Background Listener 🧵

در مرحله‌ی بعد، به یک background service نیاز داریم که روی هر نود اجرا شود. این سرویس روی کانال Redis مشترک می‌شود و کلیدها را از HybridCache محلی حذف می‌کند.

یک نکته‌ی سریع درباره‌ی self-publishing:
چون Redis Pub/Sub پیام را برای همه‌ی subscriberها ارسال می‌کند، نودی که خودش پیام invalidation را منتشر کرده هم دوباره همان پیام را دریافت می‌کند. در این پیاده‌سازی، ما دوباره همان کلید را حذف می‌کنیم. این کار تکراری ولی بی‌ضرر است و کد را ساده نگه می‌دارد. 🔁

توجه کنید که ما مستقیماً HybridCache را داخل background service تزریق کرده‌ایم. یک جایگزین این است که از IMemoryCache استفاده کنیم، چون همان L1 cache داخل HybridCache است.
public class CacheInvalidationService(
IConnectionMultiplexer connectionMultiplexer,
HybridCache hybridCache,
ILogger<CacheInvalidationService> logger)
: BackgroundService
{
private const RedisChannel Channel = RedisChannel.Literal("cache-invalidation");

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
var subscriber = connectionMultiplexer.GetSubscriber();

await subscriber.SubscribeAsync(Channel, (channel, value) =>
{
string key = value.ToString();

logger.LogInformation("Invalidating local cache for: {Key}", key);

// This removes the item from the local L1 cache
var task = hybridCache.RemoveAsync(key, stoppingToken);

if (!task.IsCompleted)
{
task.GetAwaiter().GetResult();
}
});
}
}
More from @csharpgeeks
  1. Sep 22, 2026یه مدتی قراره از دنیای NET. فاصله بگیرم، چون وقتشه برم سربازی. راستش نمیدونم این مدت رو چج…
  2. Sep 20, 2026🔥 حالا مشکل اصلی: Alert Storm فرض کن Database از دسترس خارج شده. ۱۰۰ Pod داری. هر Pod می‌…
  3. Sep 20, 2026🚨 طراحی سیستم Monitoring و Alerting در یک سیستم بزرگ فرض کن ساعت ۳ صبح است. سیستم شما با…
  4. Sep 19, 2026#Engineering_Leadership تصمیم نگرفتن هم یک تصمیم است یه چیز عجیب توی تیم‌های مهندسی: گاهی…
  5. Sep 19, 2026☑ چک‌لیست آماده‌سازی تیم، فرایندها و زیرساخت برای توسعه با AI توجه: هیچ چک‌لیستی جهان‌شمول…
  6. Sep 19, 2026📌پایان یک انتظار طولانی: اعتبارسنجی ناهمگام (Async Validation) در NET 11.
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →