This commit is contained in:
payacom
2026-08-31 20:45:41 +03:30
parent fa9f23c61d
commit 3f416a7a60
367 changed files with 621895 additions and 6443 deletions

57
utils/cache.js Normal file
View 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 }