@naturalcycles/backend-lib 9.84.1 → 9.84.2

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.
@@ -11,8 +11,10 @@ import type { Integer, NonNegativeInteger, NumberOfMilliseconds, NumberOfPercent
11
11
  * reported by older interval-based sampling.
12
12
  *
13
13
  * Beware of CPU-throttled processes (e.g. idle CloudRun instances with request-based billing):
14
- * the interval timer fires late there, and the time the process spent runnable-but-unscheduled
15
- * is recorded as event loop delay. Use `intervalMs` to detect such intervals.
14
+ * the time the process spent runnable-but-unscheduled is recorded as event loop delay,
15
+ * and the interval timer fires late (see `intervalMs`).
16
+ * Use `pause()` / `resume()` to keep such periods out of the delay samples,
17
+ * e.g. pause when the last in-flight request finishes and resume when the next one arrives.
16
18
  */
17
19
  export declare class EventLoopMonitor {
18
20
  constructor(cfg?: EventLoopMonitorCfg);
@@ -20,6 +22,7 @@ export declare class EventLoopMonitor {
20
22
  private eld;
21
23
  private lastElu;
22
24
  private lastReportedAt;
25
+ private paused;
23
26
  /**
24
27
  * Undefined until the first interval has completed.
25
28
  */
@@ -28,6 +31,22 @@ export declare class EventLoopMonitor {
28
31
  gcCount: number;
29
32
  gcTotalTime: number;
30
33
  stop(): void;
34
+ /**
35
+ * Stops sampling event loop delay until `resume()` is called.
36
+ * GC and ELU keep being tracked, and the samples recorded so far are kept.
37
+ *
38
+ * Meant for periods when the process is known to be CPU-throttled, e.g. a CloudRun instance
39
+ * (request-based billing) with no request in flight: a delay recorded there measures
40
+ * the throttling, not the application.
41
+ */
42
+ pause(): void;
43
+ /**
44
+ * Resumes sampling event loop delay after `pause()`.
45
+ * Safe to call from within the event that ended the throttled period (e.g. the middleware of
46
+ * the request that woke the instance): the histogram restarts its clock from this moment,
47
+ * so the stall that preceded it in the same loop iteration is not sampled.
48
+ */
49
+ resume(): void;
31
50
  }
32
51
  export interface EventLoopMonitorCfg {
33
52
  /**
@@ -27,8 +27,10 @@ import { monitorEventLoopDelay, performance, PerformanceObserver } from 'node:pe
27
27
  * reported by older interval-based sampling.
28
28
  *
29
29
  * Beware of CPU-throttled processes (e.g. idle CloudRun instances with request-based billing):
30
- * the interval timer fires late there, and the time the process spent runnable-but-unscheduled
31
- * is recorded as event loop delay. Use `intervalMs` to detect such intervals.
30
+ * the time the process spent runnable-but-unscheduled is recorded as event loop delay,
31
+ * and the interval timer fires late (see `intervalMs`).
32
+ * Use `pause()` / `resume()` to keep such periods out of the delay samples,
33
+ * e.g. pause when the last in-flight request finishes and resume when the next one arrives.
32
34
  */
33
35
  export class EventLoopMonitor {
34
36
  constructor(cfg = {}) {
@@ -92,6 +94,7 @@ export class EventLoopMonitor {
92
94
  eld;
93
95
  lastElu;
94
96
  lastReportedAt;
97
+ paused = false;
95
98
  /**
96
99
  * Undefined until the first interval has completed.
97
100
  */
@@ -104,4 +107,28 @@ export class EventLoopMonitor {
104
107
  this.eld.disable();
105
108
  this.po.disconnect();
106
109
  }
110
+ /**
111
+ * Stops sampling event loop delay until `resume()` is called.
112
+ * GC and ELU keep being tracked, and the samples recorded so far are kept.
113
+ *
114
+ * Meant for periods when the process is known to be CPU-throttled, e.g. a CloudRun instance
115
+ * (request-based billing) with no request in flight: a delay recorded there measures
116
+ * the throttling, not the application.
117
+ */
118
+ pause() {
119
+ this.paused = true;
120
+ this.eld.disable();
121
+ }
122
+ /**
123
+ * Resumes sampling event loop delay after `pause()`.
124
+ * Safe to call from within the event that ended the throttled period (e.g. the middleware of
125
+ * the request that woke the instance): the histogram restarts its clock from this moment,
126
+ * so the stall that preceded it in the same loop iteration is not sampled.
127
+ */
128
+ resume() {
129
+ if (!this.paused)
130
+ return;
131
+ this.paused = false;
132
+ this.eld.enable();
133
+ }
107
134
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@naturalcycles/backend-lib",
3
3
  "type": "module",
4
- "version": "9.84.1",
4
+ "version": "9.84.2",
5
5
  "dependencies": {
6
6
  "@naturalcycles/db-lib": "^10",
7
7
  "@naturalcycles/js-lib": "^15",
@@ -36,8 +36,10 @@ import type {
36
36
  * reported by older interval-based sampling.
37
37
  *
38
38
  * Beware of CPU-throttled processes (e.g. idle CloudRun instances with request-based billing):
39
- * the interval timer fires late there, and the time the process spent runnable-but-unscheduled
40
- * is recorded as event loop delay. Use `intervalMs` to detect such intervals.
39
+ * the time the process spent runnable-but-unscheduled is recorded as event loop delay,
40
+ * and the interval timer fires late (see `intervalMs`).
41
+ * Use `pause()` / `resume()` to keep such periods out of the delay samples,
42
+ * e.g. pause when the last in-flight request finishes and resume when the next one arrives.
41
43
  */
42
44
  export class EventLoopMonitor {
43
45
  constructor(cfg: EventLoopMonitorCfg = {}) {
@@ -113,6 +115,7 @@ export class EventLoopMonitor {
113
115
  private eld: ELDHistogram
114
116
  private lastElu: EventLoopUtilization
115
117
  private lastReportedAt: NumberOfMilliseconds
118
+ private paused = false
116
119
  /**
117
120
  * Undefined until the first interval has completed.
118
121
  */
@@ -127,6 +130,31 @@ export class EventLoopMonitor {
127
130
  this.po.disconnect()
128
131
  }
129
132
 
133
+ /**
134
+ * Stops sampling event loop delay until `resume()` is called.
135
+ * GC and ELU keep being tracked, and the samples recorded so far are kept.
136
+ *
137
+ * Meant for periods when the process is known to be CPU-throttled, e.g. a CloudRun instance
138
+ * (request-based billing) with no request in flight: a delay recorded there measures
139
+ * the throttling, not the application.
140
+ */
141
+ pause(): void {
142
+ this.paused = true
143
+ this.eld.disable()
144
+ }
145
+
146
+ /**
147
+ * Resumes sampling event loop delay after `pause()`.
148
+ * Safe to call from within the event that ended the throttled period (e.g. the middleware of
149
+ * the request that woke the instance): the histogram restarts its clock from this moment,
150
+ * so the stall that preceded it in the same loop iteration is not sampled.
151
+ */
152
+ resume(): void {
153
+ if (!this.paused) return
154
+ this.paused = false
155
+ this.eld.enable()
156
+ }
157
+
130
158
  // cfg: Required<EventLoopMonitorCfg>
131
159
  }
132
160