🚀 سطح 4️⃣: مقیاسپذیری با Keyed Locking
حرکت «حرفهای» 👌 در اینجا استفاده از Keyed Locking است 🔑.
ما برای هر ارز مشخص یک lock جداگانه ایجاد میکنیم. از آنجایی که تعداد ارزها محدود است 💱، این روش از نظر مصرف حافظه سنگین نیست.
ما به یک ConcurrentDictionary اضافه نیاز داریم تا semaphoreها را بهازای هر کد ارز نگهداری کنیم 🧵.
private static readonly ConcurrentDictionary<string, SemaphoreSlim> Locks = new();
// In the Handler:
var semaphore = Locks.GetOrAdd(currencyCode, _ => new SemaphoreSlim(1, 1));
if (!Cache.TryGetValue(currencyCode, out var cachedRate) &&
DateTime.UtcNow - cachedRate?.CreatedAt < CacheDuration)
{
var acquired = await semaphore.WaitAsync(TimeSpan.FromSeconds(10));
if (!acquired)
{
throw new Exception("Could not acquire lock to fetch exchange rate.");
}
try
{
// Fetch and update logic...
}
finally { semaphore.Release(); }
}
تنها چیزی که تغییر کرده، نحوهی گرفتن lock است 🔒.
حالا اگر یک thread در حال گرفتن نرخ "EUR" باشد 🇪🇺، threadهای دیگر که "JPY" را درخواست کردهاند 🇯🇵، بدون معطلی ادامه میدهند ⏩.
این مقیاسپذیرترین نسخه از cache ماست 📈.
اما… ⚠️
این راهحل فقط در حافظه کار میکند.
پس برای سیستمهای توزیعشده یا چندین instance سرور مناسب نیست 🌐.
همچنین چند edge case دیگر هم وجود دارد که میتوانی آنها را بهعنوان تمرین بررسی کنی 🧠.