@maioradv/nestjs-core 2.0.3 → 2.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -4,22 +4,30 @@ export type ResourceGuardOptions = {
|
|
|
4
4
|
cpuLimit?: number;
|
|
5
5
|
/** Memory limit in MB (RSS). Optional. */
|
|
6
6
|
memoryLimitMb?: number;
|
|
7
|
-
/** Interval in ms to check CPU/memory. Default: 2000 */
|
|
7
|
+
/** Interval in ms to check CPU/memory. Default: 2000 ms */
|
|
8
8
|
sampleIntervalMs?: number;
|
|
9
|
-
/** How long in ms the limit must be exceeded before shutdown. Default:
|
|
9
|
+
/** How long in ms the limit must be exceeded before shutdown. Default: 10000ms */
|
|
10
10
|
sustainForMs?: number;
|
|
11
|
-
/** Maximum time in ms to wait for shutdownFn before hard kill. Default:
|
|
11
|
+
/** Maximum time in ms to wait for shutdownFn before hard kill. Default: 5000ms */
|
|
12
12
|
hardKillAfterMs?: number;
|
|
13
13
|
/** Optional async shutdown function. If provided, will be called before hard exit. */
|
|
14
14
|
shutdownFn?: () => Promise<void>;
|
|
15
15
|
/** Optional NestJS LoggerService to use for logging. */
|
|
16
16
|
logger?: LoggerService;
|
|
17
|
+
/** Optional peak logging options: log when CPU/memory exceed thresholds for a sustained period. Default sustain: 3000ms */
|
|
18
|
+
logPeaks?: {
|
|
19
|
+
cpuThreshold?: number;
|
|
20
|
+
memoryThresholdMb?: number;
|
|
21
|
+
sustainMs?: number;
|
|
22
|
+
};
|
|
17
23
|
};
|
|
18
24
|
export declare class ResourceGuard {
|
|
19
25
|
private readonly opts;
|
|
20
26
|
private lastCpu;
|
|
21
27
|
private lastTime;
|
|
22
28
|
private overSince;
|
|
29
|
+
private peakCpuSince;
|
|
30
|
+
private peakMemSince;
|
|
23
31
|
private shuttingDown;
|
|
24
32
|
constructor(opts: ResourceGuardOptions);
|
|
25
33
|
/** Start monitoring CPU and memory */
|
|
@@ -7,14 +7,19 @@ class ResourceGuard {
|
|
|
7
7
|
this.lastCpu = process.cpuUsage();
|
|
8
8
|
this.lastTime = Date.now();
|
|
9
9
|
this.overSince = null;
|
|
10
|
+
this.peakCpuSince = null;
|
|
11
|
+
this.peakMemSince = null;
|
|
10
12
|
this.shuttingDown = false;
|
|
11
13
|
this.opts.sampleIntervalMs ??= 2000;
|
|
12
14
|
this.opts.sustainForMs ??= 10000;
|
|
13
15
|
this.opts.hardKillAfterMs ??= 5000;
|
|
16
|
+
if (this.opts.logPeaks) {
|
|
17
|
+
this.opts.logPeaks.sustainMs ??= 3000;
|
|
18
|
+
}
|
|
14
19
|
}
|
|
15
20
|
/** Start monitoring CPU and memory */
|
|
16
21
|
start() {
|
|
17
|
-
if (!this.opts.cpuLimit && !this.opts.memoryLimitMb)
|
|
22
|
+
if (!this.opts.cpuLimit && !this.opts.memoryLimitMb && !this.opts.logPeaks)
|
|
18
23
|
return;
|
|
19
24
|
setInterval(() => this.check(), this.opts.sampleIntervalMs).unref();
|
|
20
25
|
}
|
|
@@ -25,18 +30,21 @@ class ResourceGuard {
|
|
|
25
30
|
let over = false;
|
|
26
31
|
let currentCpuPercent = null;
|
|
27
32
|
let currentMemMb = null;
|
|
28
|
-
if
|
|
33
|
+
// compute CPU percent if needed for shutdown or peak logging
|
|
34
|
+
const needCpu = !!this.opts.cpuLimit || !!this.opts.logPeaks?.cpuThreshold;
|
|
35
|
+
if (needCpu) {
|
|
29
36
|
const now = process.cpuUsage(this.lastCpu);
|
|
30
37
|
const elapsedMs = nowTime - this.lastTime;
|
|
31
38
|
const cpuMs = (now.user + now.system) / 1000;
|
|
32
39
|
currentCpuPercent = (cpuMs / elapsedMs) * 100;
|
|
33
|
-
if (currentCpuPercent > this.opts.cpuLimit)
|
|
40
|
+
if (this.opts.cpuLimit && currentCpuPercent > this.opts.cpuLimit)
|
|
34
41
|
over = true;
|
|
35
42
|
this.lastCpu = process.cpuUsage();
|
|
36
43
|
}
|
|
37
|
-
|
|
44
|
+
const needMem = !!this.opts.memoryLimitMb || !!this.opts.logPeaks?.memoryThresholdMb;
|
|
45
|
+
if (needMem) {
|
|
38
46
|
currentMemMb = process.memoryUsage().rss / 1024 / 1024;
|
|
39
|
-
if (currentMemMb > this.opts.memoryLimitMb)
|
|
47
|
+
if (this.opts.memoryLimitMb && currentMemMb > this.opts.memoryLimitMb)
|
|
40
48
|
over = true;
|
|
41
49
|
}
|
|
42
50
|
this.lastTime = nowTime;
|
|
@@ -50,6 +58,44 @@ class ResourceGuard {
|
|
|
50
58
|
else {
|
|
51
59
|
this.overSince = null;
|
|
52
60
|
}
|
|
61
|
+
const log = (msg) => {
|
|
62
|
+
if (this.opts.logger)
|
|
63
|
+
this.opts.logger.warn(`${msg}`);
|
|
64
|
+
else
|
|
65
|
+
console.warn(`${msg}`);
|
|
66
|
+
};
|
|
67
|
+
// Peak logging (non-shutdown): CPU
|
|
68
|
+
if (this.opts.logPeaks?.cpuThreshold && currentCpuPercent !== null) {
|
|
69
|
+
if (currentCpuPercent > this.opts.logPeaks.cpuThreshold) {
|
|
70
|
+
if (!this.peakCpuSince)
|
|
71
|
+
this.peakCpuSince = nowTime;
|
|
72
|
+
const sustainMs = this.opts.logPeaks.sustainMs;
|
|
73
|
+
if (nowTime - this.peakCpuSince >= sustainMs) {
|
|
74
|
+
const msg = `CPU: ${currentCpuPercent.toFixed(1)}% (${this.opts.logPeaks.cpuThreshold}%) ${nowTime - this.peakCpuSince}ms`;
|
|
75
|
+
log(msg);
|
|
76
|
+
this.peakCpuSince = null; // avoid repeated logging until it drops below
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
this.peakCpuSince = null;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// Peak logging: Memory
|
|
84
|
+
if (this.opts.logPeaks?.memoryThresholdMb && currentMemMb !== null) {
|
|
85
|
+
if (currentMemMb > this.opts.logPeaks.memoryThresholdMb) {
|
|
86
|
+
if (!this.peakMemSince)
|
|
87
|
+
this.peakMemSince = nowTime;
|
|
88
|
+
const sustainMs = this.opts.logPeaks.sustainMs;
|
|
89
|
+
if (nowTime - this.peakMemSince >= sustainMs) {
|
|
90
|
+
const msg = `MEM: ${currentMemMb.toFixed(0)}MB (${this.opts.logPeaks.memoryThresholdMb}MB) ${nowTime - this.peakMemSince}ms`;
|
|
91
|
+
log(msg);
|
|
92
|
+
this.peakMemSince = null;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
this.peakMemSince = null;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
53
99
|
}
|
|
54
100
|
async shutdown(currentCpu, currentMem) {
|
|
55
101
|
if (this.shuttingDown)
|
|
@@ -63,7 +109,7 @@ class ResourceGuard {
|
|
|
63
109
|
};
|
|
64
110
|
const overTimeMs = this.overSince ? Date.now() - this.overSince : 0;
|
|
65
111
|
const cpuMsg = this.opts.cpuLimit ? ` CPU: ${currentCpu?.toFixed(1)}% (${this.opts.cpuLimit}%)` : '';
|
|
66
|
-
const memMsg = this.opts.memoryLimitMb ? `
|
|
112
|
+
const memMsg = this.opts.memoryLimitMb ? ` MEM: ${currentMem?.toFixed(0)}MB (${this.opts.memoryLimitMb}MB)` : '';
|
|
67
113
|
const append = [cpuMsg, memMsg, ` Exceeded for: ${overTimeMs}ms (${this.opts.sustainForMs}ms)`].filter(Boolean).join(';');
|
|
68
114
|
log(`LIMIT EXCEEDED → initiating shutdown;${append}`);
|
|
69
115
|
const hardKill = setTimeout(() => {
|