fix: 为 Logger.requestContext 添加 TTL 清理机制防止内存泄漏
长时间运行的服务中,如果 clearRequestContext 未被正确调用(如请求异常中断), requestContext Map 会持续增长导致内存泄漏。 新增: - 每个上下文条目记录 _createdAt 时间戳 - 每 60 秒定期扫描并清除超过 5 分钟的过期条目 - Map 为空时自动停止定时器,避免不必要的开销 - close() 时清理定时器
This commit is contained in:
parent
1f913a13b8
commit
2aff6013d7
1 changed files with 38 additions and 1 deletions
|
|
@ -22,6 +22,8 @@ class Logger {
|
|||
this.logStream = null;
|
||||
this.currentRequestId = null; // 当前请求ID
|
||||
this.requestContext = new Map(); // 存储请求上下文
|
||||
this.contextTTL = 5 * 60 * 1000; // 请求上下文 TTL:5 分钟
|
||||
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;
|
||||
|
|
|
|||
Loading…
Reference in a new issue