full
This commit is contained in:
57
utils/cache.js
Normal file
57
utils/cache.js
Normal file
@@ -0,0 +1,57 @@
|
||||
const { getRedisClient } = require('./redisClient')
|
||||
|
||||
// الگوی cache-aside عمومی: هر جایی یه کوئری/محاسبهی سنگین و پرتکرار داره، بهجای
|
||||
// شمارندهی incremental (که نگهداشتنِ درستش نیاز به ردیابیِ دقیقِ *همهی* نقاطِ
|
||||
// تغییر داره و راحت drift پیدا میکنه)، فقط نتیجهی همون کوئریِ فعلی رو با یه TTLِ
|
||||
// کوتاه کش میکنه. اگه Redis در دسترس نباشه، هر بار مستقیم fetchFn اجرا میشه —
|
||||
// دقیقاً همون رفتارِ قبل از اضافهشدنِ کش (کندتر، ولی همیشه درست)
|
||||
async function getOrSetCache (key, ttlSeconds, fetchFn) {
|
||||
const redis = getRedisClient()
|
||||
if (!redis) return fetchFn()
|
||||
|
||||
try {
|
||||
const cached = await redis.get(key)
|
||||
if (cached != null) return JSON.parse(cached)
|
||||
} catch (err) {
|
||||
console.error(`[cache] read error for ${key}:`, err.message)
|
||||
}
|
||||
|
||||
const fresh = await fetchFn()
|
||||
|
||||
try {
|
||||
await redis.set(key, JSON.stringify(fresh), { EX: ttlSeconds })
|
||||
} catch (err) {
|
||||
console.error(`[cache] write error for ${key}:`, err.message)
|
||||
}
|
||||
|
||||
return fresh
|
||||
}
|
||||
|
||||
// موقعِ تغییرِ داده (پیام جدید/خوندهشدنِ پیام، لایک/آنلایک، پست جدید و...) باید
|
||||
// صریحاً صدا زده بشه تا کشِ مرتبط بلافاصله باطل بشه، نه اینکه تا انقضای TTL کهنه بمونه
|
||||
async function invalidateCache (key) {
|
||||
const redis = getRedisClient()
|
||||
if (!redis) return
|
||||
try {
|
||||
await redis.del(key)
|
||||
} catch (err) {
|
||||
console.error(`[cache] invalidate error for ${key}:`, err.message)
|
||||
}
|
||||
}
|
||||
|
||||
// برای وقتی چندین کلید همزمان باید باطل بشن (مثلاً کشِ فید همهی صفحههای اکسپلور)
|
||||
async function invalidateCachePattern (pattern) {
|
||||
const redis = getRedisClient()
|
||||
if (!redis) return
|
||||
try {
|
||||
const keys = []
|
||||
for await (const key of redis.scanIterator({ MATCH: pattern, COUNT: 100 })) {
|
||||
keys.push(key)
|
||||
}
|
||||
if (keys.length) await redis.del(keys)
|
||||
} catch (err) {
|
||||
console.error(`[cache] pattern invalidate error for ${pattern}:`, err.message)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { getOrSetCache, invalidateCache, invalidateCachePattern }
|
||||
Reference in New Issue
Block a user