@naturalcycles/backend-lib 9.26.0 → 9.27.0
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.
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/server/eventLoop.util.d.ts +46 -0
- package/dist/server/eventLoop.util.js +46 -0
- package/dist/server/serverStatusMiddleware.js +5 -3
- package/package.json +1 -1
- package/src/index.ts +1 -0
- package/src/server/eventLoop.util.ts +95 -0
- package/src/server/serverStatusMiddleware.ts +5 -3
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export * from './sentry/sentry.shared.service.js';
|
|
|
3
3
|
export * from './server/asyncLocalStorageMiddleware.js';
|
|
4
4
|
export * from './server/basicAuthMiddleware.js';
|
|
5
5
|
export * from './server/bodyParserTimeoutMiddleware.js';
|
|
6
|
+
export * from './server/eventLoop.util.js';
|
|
6
7
|
export * from './server/genericErrorMiddleware.js';
|
|
7
8
|
export * from './server/logMiddleware.js';
|
|
8
9
|
export * from './server/methodOverrideMiddleware.js';
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,7 @@ export * from './sentry/sentry.shared.service.js';
|
|
|
3
3
|
export * from './server/asyncLocalStorageMiddleware.js';
|
|
4
4
|
export * from './server/basicAuthMiddleware.js';
|
|
5
5
|
export * from './server/bodyParserTimeoutMiddleware.js';
|
|
6
|
+
export * from './server/eventLoop.util.js';
|
|
6
7
|
export * from './server/genericErrorMiddleware.js';
|
|
7
8
|
export * from './server/logMiddleware.js';
|
|
8
9
|
export * from './server/methodOverrideMiddleware.js';
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { NumberOfMilliseconds, NumberOfPercent } from '@naturalcycles/js-lib/types';
|
|
2
|
+
/**
|
|
3
|
+
* @experimental
|
|
4
|
+
*/
|
|
5
|
+
export declare class EventLoopMonitor {
|
|
6
|
+
constructor(cfg?: EventLoopMonitorCfg);
|
|
7
|
+
private interval;
|
|
8
|
+
private eld;
|
|
9
|
+
private lastElu;
|
|
10
|
+
/**
|
|
11
|
+
* Undefined until the first interval has completed.
|
|
12
|
+
*/
|
|
13
|
+
lastStats?: EventLoopStats;
|
|
14
|
+
stop(): void;
|
|
15
|
+
}
|
|
16
|
+
export interface EventLoopMonitorCfg {
|
|
17
|
+
/**
|
|
18
|
+
* Defaults to 20.
|
|
19
|
+
*/
|
|
20
|
+
resolution?: NumberOfMilliseconds;
|
|
21
|
+
/**
|
|
22
|
+
* Defaults to 60_000 ms
|
|
23
|
+
*/
|
|
24
|
+
measureInterval?: NumberOfMilliseconds;
|
|
25
|
+
/**
|
|
26
|
+
* Callback to be invoked with EventLoopStats.
|
|
27
|
+
* Called every `measureInterval` milliseconds.
|
|
28
|
+
*/
|
|
29
|
+
onStats?: (stats: EventLoopStats) => void;
|
|
30
|
+
}
|
|
31
|
+
export interface EventLoopStats {
|
|
32
|
+
p50: NumberOfMilliseconds;
|
|
33
|
+
p90: NumberOfMilliseconds;
|
|
34
|
+
p99: NumberOfMilliseconds;
|
|
35
|
+
max: NumberOfMilliseconds;
|
|
36
|
+
mean: NumberOfMilliseconds;
|
|
37
|
+
/**
|
|
38
|
+
* EventLoopUtilization in percent.
|
|
39
|
+
*
|
|
40
|
+
* Calculated as:
|
|
41
|
+
* idle: <nanoseconds event loop was idle>,
|
|
42
|
+
* active: <nanoseconds event loop was busy>,
|
|
43
|
+
* utilization: active / (idle + active)
|
|
44
|
+
*/
|
|
45
|
+
elu: NumberOfPercent;
|
|
46
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { monitorEventLoopDelay, performance } from 'node:perf_hooks';
|
|
2
|
+
/**
|
|
3
|
+
* @experimental
|
|
4
|
+
*/
|
|
5
|
+
export class EventLoopMonitor {
|
|
6
|
+
constructor(cfg = {}) {
|
|
7
|
+
const { resolution = 20, measureInterval = 60_000 } = cfg;
|
|
8
|
+
this.eld = monitorEventLoopDelay({ resolution });
|
|
9
|
+
this.eld.enable();
|
|
10
|
+
this.lastElu = performance.eventLoopUtilization();
|
|
11
|
+
this.interval = setInterval(() => {
|
|
12
|
+
// Delay stats are reported in **nanoseconds**
|
|
13
|
+
const { eld } = this;
|
|
14
|
+
const p50 = Math.round(eld.percentile(50) / 1e6);
|
|
15
|
+
const p90 = Math.round(eld.percentile(90) / 1e6);
|
|
16
|
+
const p99 = Math.round(eld.percentile(99) / 1e6);
|
|
17
|
+
const max = Math.round(eld.max / 1e6);
|
|
18
|
+
const mean = Math.round(eld.mean / 1e6);
|
|
19
|
+
const currentElu = performance.eventLoopUtilization();
|
|
20
|
+
const deltaElu = performance.eventLoopUtilization(this.lastElu, currentElu);
|
|
21
|
+
this.lastElu = currentElu;
|
|
22
|
+
const elu = Math.round(deltaElu.utilization * 100);
|
|
23
|
+
this.lastStats = {
|
|
24
|
+
p50,
|
|
25
|
+
p90,
|
|
26
|
+
p99,
|
|
27
|
+
max,
|
|
28
|
+
mean,
|
|
29
|
+
elu,
|
|
30
|
+
};
|
|
31
|
+
cfg.onStats?.(this.lastStats);
|
|
32
|
+
eld.reset();
|
|
33
|
+
}, measureInterval);
|
|
34
|
+
}
|
|
35
|
+
interval;
|
|
36
|
+
eld;
|
|
37
|
+
lastElu;
|
|
38
|
+
/**
|
|
39
|
+
* Undefined until the first interval has completed.
|
|
40
|
+
*/
|
|
41
|
+
lastStats;
|
|
42
|
+
stop() {
|
|
43
|
+
this.interval.close();
|
|
44
|
+
this.eld.disable();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -10,9 +10,11 @@ export function serverStatusMiddleware(projectDir, extra) {
|
|
|
10
10
|
};
|
|
11
11
|
}
|
|
12
12
|
export function getServerStatusData(projectDir = process.cwd(), extra) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
let deployBuildTime = DEPLOY_BUILD_TIME;
|
|
14
|
+
if (!deployBuildTime) {
|
|
15
|
+
const { ts } = getDeployInfo(projectDir);
|
|
16
|
+
deployBuildTime = localTime(ts).toPretty();
|
|
17
|
+
}
|
|
16
18
|
return _filterNullishValues({
|
|
17
19
|
nodeProcessStarted: getStartedStr(),
|
|
18
20
|
deployBuildTime,
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -3,6 +3,7 @@ export * from './sentry/sentry.shared.service.js'
|
|
|
3
3
|
export * from './server/asyncLocalStorageMiddleware.js'
|
|
4
4
|
export * from './server/basicAuthMiddleware.js'
|
|
5
5
|
export * from './server/bodyParserTimeoutMiddleware.js'
|
|
6
|
+
export * from './server/eventLoop.util.js'
|
|
6
7
|
export * from './server/genericErrorMiddleware.js'
|
|
7
8
|
export * from './server/logMiddleware.js'
|
|
8
9
|
export * from './server/methodOverrideMiddleware.js'
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { EventLoopUtilization, IntervalHistogram } from 'node:perf_hooks'
|
|
2
|
+
import { monitorEventLoopDelay, performance } from 'node:perf_hooks'
|
|
3
|
+
import type { NumberOfMilliseconds, NumberOfPercent } from '@naturalcycles/js-lib/types'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @experimental
|
|
7
|
+
*/
|
|
8
|
+
export class EventLoopMonitor {
|
|
9
|
+
constructor(cfg: EventLoopMonitorCfg = {}) {
|
|
10
|
+
const { resolution = 20, measureInterval = 60_000 } = cfg
|
|
11
|
+
|
|
12
|
+
this.eld = monitorEventLoopDelay({ resolution })
|
|
13
|
+
this.eld.enable()
|
|
14
|
+
|
|
15
|
+
this.lastElu = performance.eventLoopUtilization()
|
|
16
|
+
|
|
17
|
+
this.interval = setInterval(() => {
|
|
18
|
+
// Delay stats are reported in **nanoseconds**
|
|
19
|
+
const { eld } = this
|
|
20
|
+
const p50 = Math.round(eld.percentile(50) / 1e6)
|
|
21
|
+
const p90 = Math.round(eld.percentile(90) / 1e6)
|
|
22
|
+
const p99 = Math.round(eld.percentile(99) / 1e6)
|
|
23
|
+
const max = Math.round(eld.max / 1e6)
|
|
24
|
+
const mean = Math.round(eld.mean / 1e6)
|
|
25
|
+
|
|
26
|
+
const currentElu = performance.eventLoopUtilization()
|
|
27
|
+
const deltaElu = performance.eventLoopUtilization(this.lastElu, currentElu)
|
|
28
|
+
this.lastElu = currentElu
|
|
29
|
+
|
|
30
|
+
const elu = Math.round(deltaElu.utilization * 100)
|
|
31
|
+
|
|
32
|
+
this.lastStats = {
|
|
33
|
+
p50,
|
|
34
|
+
p90,
|
|
35
|
+
p99,
|
|
36
|
+
max,
|
|
37
|
+
mean,
|
|
38
|
+
elu,
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
cfg.onStats?.(this.lastStats)
|
|
42
|
+
|
|
43
|
+
eld.reset()
|
|
44
|
+
}, measureInterval)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
private interval: NodeJS.Timeout
|
|
48
|
+
private eld: IntervalHistogram
|
|
49
|
+
private lastElu: EventLoopUtilization
|
|
50
|
+
/**
|
|
51
|
+
* Undefined until the first interval has completed.
|
|
52
|
+
*/
|
|
53
|
+
lastStats?: EventLoopStats
|
|
54
|
+
|
|
55
|
+
stop(): void {
|
|
56
|
+
this.interval.close()
|
|
57
|
+
this.eld.disable()
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// cfg: Required<EventLoopMonitorCfg>
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface EventLoopMonitorCfg {
|
|
64
|
+
/**
|
|
65
|
+
* Defaults to 20.
|
|
66
|
+
*/
|
|
67
|
+
resolution?: NumberOfMilliseconds
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Defaults to 60_000 ms
|
|
71
|
+
*/
|
|
72
|
+
measureInterval?: NumberOfMilliseconds
|
|
73
|
+
/**
|
|
74
|
+
* Callback to be invoked with EventLoopStats.
|
|
75
|
+
* Called every `measureInterval` milliseconds.
|
|
76
|
+
*/
|
|
77
|
+
onStats?: (stats: EventLoopStats) => void
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface EventLoopStats {
|
|
81
|
+
p50: NumberOfMilliseconds
|
|
82
|
+
p90: NumberOfMilliseconds
|
|
83
|
+
p99: NumberOfMilliseconds
|
|
84
|
+
max: NumberOfMilliseconds
|
|
85
|
+
mean: NumberOfMilliseconds
|
|
86
|
+
/**
|
|
87
|
+
* EventLoopUtilization in percent.
|
|
88
|
+
*
|
|
89
|
+
* Calculated as:
|
|
90
|
+
* idle: <nanoseconds event loop was idle>,
|
|
91
|
+
* active: <nanoseconds event loop was busy>,
|
|
92
|
+
* utilization: active / (idle + active)
|
|
93
|
+
*/
|
|
94
|
+
elu: NumberOfPercent
|
|
95
|
+
}
|
|
@@ -28,9 +28,11 @@ export function getServerStatusData(
|
|
|
28
28
|
projectDir: string = process.cwd(),
|
|
29
29
|
extra?: any,
|
|
30
30
|
): Record<string, any> {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
let deployBuildTime = DEPLOY_BUILD_TIME
|
|
32
|
+
if (!deployBuildTime) {
|
|
33
|
+
const { ts } = getDeployInfo(projectDir)
|
|
34
|
+
deployBuildTime = localTime(ts).toPretty()
|
|
35
|
+
}
|
|
34
36
|
|
|
35
37
|
return _filterNullishValues({
|
|
36
38
|
nodeProcessStarted: getStartedStr(),
|