alexagame / db /cache.js
hansaka01's picture
Upload 54 files
0684e4d verified
Raw
History Blame Contribute Delete
2.05 kB
/**
* Simple in-memory cache for MongoDB queries.
* TTL-based, auto-evicts expired entries.
* Reduces DB load for frequent reads (wallet checks, leaderboard, etc.)
*/
const User = require('../models/User');
const cache = new Map();
const DEFAULT_TTL = 15000; // 15 seconds
const LEADERBOARD_TTL = 30000; // 30 seconds
function getCacheKey(type, id) { return `${type}:${id}`; }
function setCache(key, data, ttl = DEFAULT_TTL) {
cache.set(key, { data, expires: Date.now() + ttl });
}
function getCache(key) {
const entry = cache.get(key);
if (!entry) return null;
if (Date.now() > entry.expires) { cache.delete(key); return null; }
return entry.data;
}
function invalidate(userId) {
// Clear all cache entries for this user
for (const [key] of cache) {
if (key.includes(userId)) cache.delete(key);
}
}
// Periodic cleanup of expired entries (every 60s)
setInterval(() => {
const now = Date.now();
for (const [key, entry] of cache) {
if (now > entry.expires) cache.delete(key);
}
}, 60000);
/**
* Get user with cache. Returns lean object.
*/
async function getUser(userId) {
const key = getCacheKey('user', userId);
const cached = getCache(key);
if (cached) return cached;
const user = await User.findOne({ userId }).lean().maxTimeMS(5000);
if (user) setCache(key, user);
return user;
}
/**
* Get or create user.
*/
async function getOrCreateUser(userId, extra = {}) {
let user = await getUser(userId);
if (!user) {
user = (await User.create({ userId, ...extra })).toObject();
setCache(getCacheKey('user', userId), user);
}
return user;
}
/**
* Update user and invalidate cache.
*/
async function saveUser(userId, updateFn) {
let user = await User.findOne({ userId }) || await User.create({ userId });
await updateFn(user);
await user.save();
invalidate(userId);
return user;
}
module.exports = { getUser, getOrCreateUser, saveUser, invalidate, setCache, getCache, getCacheKey, LEADERBOARD_TTL };