fix: searchCache/commentCache 写入时清扫过期条目并限制大小上限 (#345)
cache-util.js: - 新增 sweepExpiredCache(),写入前按 TTL 遍历删除过期条目 - setSearchCache / setCommentCache 写入后检查 Map.size,超过 500 则移除最早条目 作为 TTL 清扫后的安全兜底 globals.js: - getConfig() Proxy 实例懒初始化后缓存复用,不再每次新建 cookie-util.js: - handleQRCheck 增加 finally 块,检查完成后清理 qrLoginSessions
This commit is contained in:
1 parent
91e563ab5c
commit
d02e84f71f
3 files changed
+52
-3
No files matched your search
@@ -152,12 +152,14 @@ export const Globals = {
|
||||
*/
|
||||
/**
|
||||
* 获取全局配置对象(单例,可修改)
|
||||
* 使用 Proxy 保持接口兼容性,实例懒初始化后缓存复用避免每次新建
|
||||
* @returns {Object} 全局配置对象本身
|
||||
*/
|
||||
getConfig() {
|
||||
// 使用 Proxy 保持接口兼容性
|
||||
if (this._configProxy) return this._configProxy;
|
||||
|
||||
const self = this;
|
||||
return new Proxy({}, {
|
||||
this._configProxy = new Proxy({}, {
|
||||
get(target, prop) {
|
||||
// 优先返回 envs 中的属性(保持原有的平铺效果)
|
||||
if (prop in self.envs) {
|
||||
@@ -186,6 +188,8 @@ export const Globals = {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
return this._configProxy;
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -104,6 +104,25 @@ function getActiveSearchCacheEntries() {
|
||||
return activeEntries;
|
||||
}
|
||||
|
||||
// 清除 Map 中所有已超过 TTL 的过期条目
|
||||
// 使用 Map 自身的迭代器遍历并删除,不依赖 getActiveSearchCacheEntries 的返回值
|
||||
function sweepExpiredCache(cacheMap, cacheMinutes, cacheName) {
|
||||
const now = Date.now();
|
||||
let sweptCount = 0;
|
||||
|
||||
for (const [key, entry] of cacheMap.entries()) {
|
||||
const ageMinutes = (now - entry.timestamp) / (1000 * 60);
|
||||
if (ageMinutes > cacheMinutes) {
|
||||
cacheMap.delete(key);
|
||||
sweptCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (sweptCount > 0) {
|
||||
log("info", `[Cache] ${cacheName} TTL 扫描完毕,已移除 ${sweptCount} 个过期条目,剩余 ${cacheMap.size} 个`);
|
||||
}
|
||||
}
|
||||
|
||||
function matchesAnimeId(anime, idStr) {
|
||||
return String(anime?.animeId) === idStr || String(anime?.bangumiId) === idStr;
|
||||
}
|
||||
@@ -279,12 +298,22 @@ export function getSearchCache(keyword, detailsMap = null) {
|
||||
export function setSearchCache(keyword, results, detailsMap = null) {
|
||||
const details = collectUniqueAnimeDetails(detailsMap);
|
||||
|
||||
// 写入前先清理所有过期条目
|
||||
sweepExpiredCache(globals.searchCache, globals.searchCacheMinutes, 'searchCache');
|
||||
|
||||
globals.searchCache.set(keyword, {
|
||||
results: results,
|
||||
details: details,
|
||||
timestamp: Date.now()
|
||||
});
|
||||
|
||||
// TTL 清理后仍未降回上限,则按插入顺序移除最早条目作为安全兜底
|
||||
if (globals.searchCache.size > 500) {
|
||||
const oldestKey = globals.searchCache.keys().next().value;
|
||||
globals.searchCache.delete(oldestKey);
|
||||
log("info", `[Cache] searchCache TTL清理后仍达上限,已移除最早条目: ${oldestKey}`);
|
||||
}
|
||||
|
||||
log("info", `[Cache] Cached search results for "${keyword}" (${results.length} animes)`);
|
||||
}
|
||||
|
||||
@@ -319,11 +348,21 @@ export function getCommentCache(videoUrl) {
|
||||
|
||||
// 设置弹幕缓存
|
||||
export function setCommentCache(videoUrl, comments) {
|
||||
// 写入前先清理所有过期条目
|
||||
sweepExpiredCache(globals.commentCache, globals.commentCacheMinutes, 'commentCache');
|
||||
|
||||
globals.commentCache.set(videoUrl, {
|
||||
comments: comments,
|
||||
timestamp: Date.now()
|
||||
});
|
||||
|
||||
// TTL 清理后仍未降回上限,则按插入顺序移除最早条目作为安全兜底
|
||||
if (globals.commentCache.size > 500) {
|
||||
const oldestKey = globals.commentCache.keys().next().value;
|
||||
globals.commentCache.delete(oldestKey);
|
||||
log("info", `[Cache] commentCache TTL清理后仍达上限,已移除最早条目: ${oldestKey}`);
|
||||
}
|
||||
|
||||
log("info", `[Cache] Cached comments for "${videoUrl}" (${comments.length} comments)`);
|
||||
}
|
||||
|
||||
|
||||
@@ -327,9 +327,10 @@ function extractLoginCookieFromResponse(response) {
|
||||
* 检查二维码扫描状态
|
||||
*/
|
||||
export async function handleQRCheck(request) {
|
||||
let qrcodeKey = null;
|
||||
try {
|
||||
const body = await request.json();
|
||||
const qrcodeKey = body.qrcodeKey || body.qrcode_key;
|
||||
qrcodeKey = body.qrcodeKey || body.qrcode_key;
|
||||
|
||||
if (!qrcodeKey) {
|
||||
return jsonResponse({ success: false, message: '缺少qrcodeKey参数' }, 400);
|
||||
@@ -389,6 +390,11 @@ export async function handleQRCheck(request) {
|
||||
return jsonResponse(result);
|
||||
} catch (error) {
|
||||
return jsonResponse({ success: false, message: error.message }, 500);
|
||||
} finally {
|
||||
// 检查完成后清理会话记录,防止长期运行后内存累积
|
||||
if (qrcodeKey) {
|
||||
qrLoginSessions.delete(qrcodeKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user