Merge pull request #342 from lly835/fix/logger-context-memory-leak

fix: 为 Logger.requestContext 添加 TTL 清理机制防止内存泄漏
This commit is contained in:
何夕2077 2026-02-27 11:12:36 +08:00 committed by GitHub
commit 328bdcee43
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -22,6 +22,8 @@ class Logger {
this.logStream = null;
this.currentRequestId = null; // 当前请求ID
this.requestContext = new Map(); // 存储请求上下文
this.contextTTL = 5 * 60 * 1000; // 请求上下文 TTL5 分钟
this._contextCleanupTimer = null;
this.levels = {
debug: 0,
info: 1,
@ -87,7 +89,8 @@ class Logger {
requestId = randomUUID().substring(0, 8);
}
this.currentRequestId = requestId;
this.requestContext.set(requestId, context);
this.requestContext.set(requestId, { ...context, _createdAt: Date.now() });
this._ensureContextCleanup();
return requestId;
}
@ -120,6 +123,36 @@ class Logger {
this.currentRequestId = null;
}
/**
* 启动定期清理过期请求上下文的定时器防止内存泄漏
* 60 秒扫描一次清除超过 contextTTL 的条目
*/
_ensureContextCleanup() {
if (this._contextCleanupTimer) return;
this._contextCleanupTimer = setInterval(() => {
const now = Date.now();
let cleaned = 0;
for (const [id, ctx] of this.requestContext) {
if (now - (ctx._createdAt || 0) > this.contextTTL) {
this.requestContext.delete(id);
cleaned++;
}
}
if (cleaned > 0) {
this.log('warn', [`[Logger] Cleaned ${cleaned} stale request context(s) (TTL: ${this.contextTTL}ms)`]);
}
// 当 Map 为空时停止定时器
if (this.requestContext.size === 0) {
clearInterval(this._contextCleanupTimer);
this._contextCleanupTimer = null;
}
}, 60_000);
// 不阻止进程退出
if (this._contextCleanupTimer.unref) {
this._contextCleanupTimer.unref();
}
}
/**
* 格式化日志消息
* @param {string} level - 日志级别
@ -310,6 +343,10 @@ class Logger {
* 关闭日志流
*/
close() {
if (this._contextCleanupTimer) {
clearInterval(this._contextCleanupTimer);
this._contextCleanupTimer = null;
}
if (this.logStream && !this.logStream.destroyed) {
this.logStream.end();
this.logStream = null;