@naturalcycles/nodejs-lib 15.101.0 → 15.103.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/script/runScript.js +3 -2
- package/dist/stream/index.d.ts +1 -0
- package/dist/stream/index.js +1 -0
- package/dist/stream/pipeline.d.ts +2 -0
- package/dist/stream/pipeline.js +5 -0
- package/dist/stream/transform/transformThrottleByRSS.d.ts +43 -0
- package/dist/stream/transform/transformThrottleByRSS.js +89 -0
- package/package.json +1 -1
- package/src/script/runScript.ts +4 -3
- package/src/stream/index.ts +1 -0
- package/src/stream/pipeline.ts +7 -0
- package/src/stream/transform/transformThrottleByRSS.ts +150 -0
package/dist/script/runScript.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import os from 'node:os';
|
|
2
|
-
import {
|
|
2
|
+
import { AsyncManager } from '@naturalcycles/js-lib';
|
|
3
3
|
import { setGlobalStringifyFunction } from '@naturalcycles/js-lib/string/stringify.js';
|
|
4
4
|
import { dimGrey } from '../colors/colors.js';
|
|
5
5
|
import { loadEnvFileIfExists } from '../node.util.js';
|
|
@@ -45,9 +45,10 @@ export function runScript(fn, opt = {}) {
|
|
|
45
45
|
void (async () => {
|
|
46
46
|
try {
|
|
47
47
|
await fn();
|
|
48
|
-
await pDelay(); // to ensure all async operations are completed
|
|
49
48
|
if (DEBUG_RUN_SCRIPT)
|
|
50
49
|
logger.log(`runScript promise resolved`);
|
|
50
|
+
// to ensure all async operations are completed (with a timeout)
|
|
51
|
+
await AsyncManager.allDone(600_000);
|
|
51
52
|
if (!noExit) {
|
|
52
53
|
setImmediate(() => process.exit(0));
|
|
53
54
|
}
|
package/dist/stream/index.d.ts
CHANGED
|
@@ -23,6 +23,7 @@ export * from './transform/transformOffset.js';
|
|
|
23
23
|
export * from './transform/transformSplit.js';
|
|
24
24
|
export * from './transform/transformTap.js';
|
|
25
25
|
export * from './transform/transformThrottle.js';
|
|
26
|
+
export * from './transform/transformThrottleByRSS.js';
|
|
26
27
|
export * from './transform/transformWarmup.js';
|
|
27
28
|
export * from './transform/worker/baseWorkerClass.js';
|
|
28
29
|
export * from './transform/worker/transformMultiThreaded.js';
|
package/dist/stream/index.js
CHANGED
|
@@ -23,6 +23,7 @@ export * from './transform/transformOffset.js';
|
|
|
23
23
|
export * from './transform/transformSplit.js';
|
|
24
24
|
export * from './transform/transformTap.js';
|
|
25
25
|
export * from './transform/transformThrottle.js';
|
|
26
|
+
export * from './transform/transformThrottleByRSS.js';
|
|
26
27
|
export * from './transform/transformWarmup.js';
|
|
27
28
|
export * from './transform/worker/baseWorkerClass.js';
|
|
28
29
|
export * from './transform/worker/transformMultiThreaded.js';
|
|
@@ -9,6 +9,7 @@ import type { TransformMapSimpleOptions } from './transform/transformMapSimple.j
|
|
|
9
9
|
import type { TransformMapSyncOptions } from './transform/transformMapSync.js';
|
|
10
10
|
import type { TransformOffsetOptions } from './transform/transformOffset.js';
|
|
11
11
|
import type { TransformThrottleOptions } from './transform/transformThrottle.js';
|
|
12
|
+
import type { TransformThrottleByRSSOptions } from './transform/transformThrottleByRSS.js';
|
|
12
13
|
import type { TransformWarmupOptions } from './transform/transformWarmup.js';
|
|
13
14
|
export declare class Pipeline<T = unknown> {
|
|
14
15
|
private readonly source;
|
|
@@ -70,6 +71,7 @@ export declare class Pipeline<T = unknown> {
|
|
|
70
71
|
tap(fn: AsyncIndexedMapper<T, any>, opt?: TransformOptions): this;
|
|
71
72
|
tapSync(fn: IndexedMapper<T, any>, opt?: TransformOptions): this;
|
|
72
73
|
throttle(opt: TransformThrottleOptions): this;
|
|
74
|
+
throttleByRSS(opt: TransformThrottleByRSSOptions): this;
|
|
73
75
|
/**
|
|
74
76
|
* @experimental to be removed after transformMap2 is stable
|
|
75
77
|
*/
|
package/dist/stream/pipeline.js
CHANGED
|
@@ -24,6 +24,7 @@ import { transformOffset } from './transform/transformOffset.js';
|
|
|
24
24
|
import { transformSplitOnNewline } from './transform/transformSplit.js';
|
|
25
25
|
import { transformTap, transformTapSync } from './transform/transformTap.js';
|
|
26
26
|
import { transformThrottle } from './transform/transformThrottle.js';
|
|
27
|
+
import { transformThrottleByRSS } from './transform/transformThrottleByRSS.js';
|
|
27
28
|
import { transformWarmup } from './transform/transformWarmup.js';
|
|
28
29
|
import { writablePushToArray } from './writable/writablePushToArray.js';
|
|
29
30
|
import { writableVoid } from './writable/writableVoid.js';
|
|
@@ -175,6 +176,10 @@ export class Pipeline {
|
|
|
175
176
|
this.transforms.push(transformThrottle(opt));
|
|
176
177
|
return this;
|
|
177
178
|
}
|
|
179
|
+
throttleByRSS(opt) {
|
|
180
|
+
this.transforms.push(transformThrottleByRSS(opt));
|
|
181
|
+
return this;
|
|
182
|
+
}
|
|
178
183
|
/**
|
|
179
184
|
* @experimental to be removed after transformMap2 is stable
|
|
180
185
|
*/
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { Integer, NumberOfMilliseconds } from '@naturalcycles/js-lib/types';
|
|
2
|
+
import type { TransformOptions, TransformTyped } from '../stream.model.js';
|
|
3
|
+
export interface TransformThrottleByRSSOptions extends TransformOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Maximum RSS (Resident Set Size) in megabytes.
|
|
6
|
+
* When process RSS exceeds this value, the stream will pause
|
|
7
|
+
* until RSS drops below the threshold.
|
|
8
|
+
*/
|
|
9
|
+
maxRSS: Integer;
|
|
10
|
+
/**
|
|
11
|
+
* How often to re-check RSS (in milliseconds) while paused.
|
|
12
|
+
*
|
|
13
|
+
* @default 5000
|
|
14
|
+
*/
|
|
15
|
+
pollInterval?: NumberOfMilliseconds;
|
|
16
|
+
/**
|
|
17
|
+
* If this timeout is reached while RSS is above the limit -
|
|
18
|
+
* the transform will "give up", log the bold warning, and "open the gateways".
|
|
19
|
+
* Things will likely OOM after that, but at least it will not "hang forever".
|
|
20
|
+
*
|
|
21
|
+
* @default 30 minutes
|
|
22
|
+
*/
|
|
23
|
+
pollTimeout?: NumberOfMilliseconds;
|
|
24
|
+
/**
|
|
25
|
+
* What to do if pollTimeout is reached.
|
|
26
|
+
* 'open-the-floodgates' will disable this throttle completely (YOLO).
|
|
27
|
+
* 'throw' will throw an error, which will destroy the stream/Pipeline.
|
|
28
|
+
*
|
|
29
|
+
* @default 'open-the-floodgates'
|
|
30
|
+
*/
|
|
31
|
+
onPollTimeout?: 'open-the-floodgates' | 'throw';
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Throttles the stream based on process memory (RSS) usage.
|
|
35
|
+
* When RSS exceeds `maxRSS` (in megabytes), the stream pauses
|
|
36
|
+
* and periodically re-checks until RSS drops below the threshold.
|
|
37
|
+
*
|
|
38
|
+
* Useful for pipelines that process large amounts of data and
|
|
39
|
+
* may cause memory pressure (e.g. database imports, file processing).
|
|
40
|
+
*
|
|
41
|
+
* @experimental
|
|
42
|
+
*/
|
|
43
|
+
export declare function transformThrottleByRSS<T>(opt: TransformThrottleByRSSOptions): TransformTyped<T, T>;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { Transform } from 'node:stream';
|
|
2
|
+
import { _mb } from '@naturalcycles/js-lib';
|
|
3
|
+
import { _ms, localTime } from '@naturalcycles/js-lib/datetime';
|
|
4
|
+
import { createCommonLoggerAtLevel } from '@naturalcycles/js-lib/log';
|
|
5
|
+
import { pDefer } from '@naturalcycles/js-lib/promise/pDefer.js';
|
|
6
|
+
/**
|
|
7
|
+
* Throttles the stream based on process memory (RSS) usage.
|
|
8
|
+
* When RSS exceeds `maxRSS` (in megabytes), the stream pauses
|
|
9
|
+
* and periodically re-checks until RSS drops below the threshold.
|
|
10
|
+
*
|
|
11
|
+
* Useful for pipelines that process large amounts of data and
|
|
12
|
+
* may cause memory pressure (e.g. database imports, file processing).
|
|
13
|
+
*
|
|
14
|
+
* @experimental
|
|
15
|
+
*/
|
|
16
|
+
export function transformThrottleByRSS(opt) {
|
|
17
|
+
const { maxRSS, pollInterval = 5000, pollTimeout = 30 * 60_000, // 30 min
|
|
18
|
+
onPollTimeout = 'open-the-floodgates', objectMode = true, highWaterMark, } = opt;
|
|
19
|
+
const maxRSSBytes = maxRSS * 1024 * 1024;
|
|
20
|
+
let lock;
|
|
21
|
+
let pollTimer;
|
|
22
|
+
let rssCheckTimer;
|
|
23
|
+
let lastRSS = 0;
|
|
24
|
+
let pausedSince = 0;
|
|
25
|
+
let disabled = false;
|
|
26
|
+
const logger = createCommonLoggerAtLevel(opt.logger, opt.logLevel);
|
|
27
|
+
return new Transform({
|
|
28
|
+
objectMode,
|
|
29
|
+
highWaterMark,
|
|
30
|
+
async transform(item, _, cb) {
|
|
31
|
+
if (lock) {
|
|
32
|
+
try {
|
|
33
|
+
await lock;
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
cb(err);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (!disabled && lastRSS > maxRSSBytes && !lock) {
|
|
41
|
+
lock = pDefer();
|
|
42
|
+
pausedSince = Date.now();
|
|
43
|
+
logger.log(`${localTime.now().toPretty()} transformThrottleByRSS paused: RSS ${_mb(lastRSS)} > ${maxRSS} MB`);
|
|
44
|
+
pollTimer = setTimeout(() => pollRSS(), pollInterval);
|
|
45
|
+
}
|
|
46
|
+
cb(null, item);
|
|
47
|
+
},
|
|
48
|
+
construct(cb) {
|
|
49
|
+
// Start periodic RSS checking
|
|
50
|
+
checkRSS();
|
|
51
|
+
cb();
|
|
52
|
+
},
|
|
53
|
+
final(cb) {
|
|
54
|
+
clearTimeout(pollTimer);
|
|
55
|
+
clearTimeout(rssCheckTimer);
|
|
56
|
+
cb();
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
function checkRSS() {
|
|
60
|
+
lastRSS = process.memoryUsage.rss();
|
|
61
|
+
rssCheckTimer = setTimeout(() => checkRSS(), pollInterval);
|
|
62
|
+
}
|
|
63
|
+
function pollRSS() {
|
|
64
|
+
const rss = lastRSS;
|
|
65
|
+
if (rss <= maxRSSBytes) {
|
|
66
|
+
logger.log(`${localTime.now().toPretty()} transformThrottleByRSS resumed: RSS ${_mb(rss)} <= ${maxRSS} MB`);
|
|
67
|
+
lock.resolve();
|
|
68
|
+
lock = undefined;
|
|
69
|
+
}
|
|
70
|
+
else if (pollTimeout && Date.now() - pausedSince >= pollTimeout) {
|
|
71
|
+
clearTimeout(rssCheckTimer);
|
|
72
|
+
if (onPollTimeout === 'throw') {
|
|
73
|
+
lock.reject(new Error(`transformThrottleByRSS pollTimeout of ${_ms(pollTimeout)} reached, RSS ${_mb(rss)} still > ${maxRSS} MB`));
|
|
74
|
+
lock = undefined;
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
// open-the-floodgates
|
|
78
|
+
logger.error(`${localTime.now().toPretty()} transformThrottleByRSS: pollTimeout of ${_ms(pollTimeout)} reached, RSS ${_mb(rss)} still > ${maxRSS} MB — DISABLING THROTTLE`);
|
|
79
|
+
disabled = true;
|
|
80
|
+
lock.resolve();
|
|
81
|
+
lock = undefined;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
logger.log(`${localTime.now().toPretty()} transformThrottleByRSS still paused: RSS ${_mb(rss)} > ${maxRSS} MB, rechecking in ${_ms(pollInterval)}`);
|
|
86
|
+
pollTimer = setTimeout(() => pollRSS(), pollInterval);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
package/package.json
CHANGED
package/src/script/runScript.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import os from 'node:os'
|
|
2
|
+
import { AsyncManager } from '@naturalcycles/js-lib'
|
|
2
3
|
import type { CommonLogger } from '@naturalcycles/js-lib/log'
|
|
3
|
-
import { pDelay } from '@naturalcycles/js-lib/promise/pDelay.js'
|
|
4
4
|
import { setGlobalStringifyFunction } from '@naturalcycles/js-lib/string/stringify.js'
|
|
5
5
|
import type { AnyObject } from '@naturalcycles/js-lib/types'
|
|
6
6
|
import { dimGrey } from '../colors/colors.js'
|
|
@@ -76,10 +76,11 @@ export function runScript(fn: (...args: any[]) => any, opt: RunScriptOptions = {
|
|
|
76
76
|
try {
|
|
77
77
|
await fn()
|
|
78
78
|
|
|
79
|
-
await pDelay() // to ensure all async operations are completed
|
|
80
|
-
|
|
81
79
|
if (DEBUG_RUN_SCRIPT) logger.log(`runScript promise resolved`)
|
|
82
80
|
|
|
81
|
+
// to ensure all async operations are completed (with a timeout)
|
|
82
|
+
await AsyncManager.allDone(600_000)
|
|
83
|
+
|
|
83
84
|
if (!noExit) {
|
|
84
85
|
setImmediate(() => process.exit(0))
|
|
85
86
|
}
|
package/src/stream/index.ts
CHANGED
|
@@ -23,6 +23,7 @@ export * from './transform/transformOffset.js'
|
|
|
23
23
|
export * from './transform/transformSplit.js'
|
|
24
24
|
export * from './transform/transformTap.js'
|
|
25
25
|
export * from './transform/transformThrottle.js'
|
|
26
|
+
export * from './transform/transformThrottleByRSS.js'
|
|
26
27
|
export * from './transform/transformWarmup.js'
|
|
27
28
|
export * from './transform/worker/baseWorkerClass.js'
|
|
28
29
|
export * from './transform/worker/transformMultiThreaded.js'
|
package/src/stream/pipeline.ts
CHANGED
|
@@ -51,6 +51,8 @@ import { transformSplitOnNewline } from './transform/transformSplit.js'
|
|
|
51
51
|
import { transformTap, transformTapSync } from './transform/transformTap.js'
|
|
52
52
|
import { transformThrottle } from './transform/transformThrottle.js'
|
|
53
53
|
import type { TransformThrottleOptions } from './transform/transformThrottle.js'
|
|
54
|
+
import { transformThrottleByRSS } from './transform/transformThrottleByRSS.js'
|
|
55
|
+
import type { TransformThrottleByRSSOptions } from './transform/transformThrottleByRSS.js'
|
|
54
56
|
import { transformWarmup } from './transform/transformWarmup.js'
|
|
55
57
|
import type { TransformWarmupOptions } from './transform/transformWarmup.js'
|
|
56
58
|
import { writablePushToArray } from './writable/writablePushToArray.js'
|
|
@@ -249,6 +251,11 @@ export class Pipeline<T = unknown> {
|
|
|
249
251
|
return this
|
|
250
252
|
}
|
|
251
253
|
|
|
254
|
+
throttleByRSS(opt: TransformThrottleByRSSOptions): this {
|
|
255
|
+
this.transforms.push(transformThrottleByRSS(opt))
|
|
256
|
+
return this
|
|
257
|
+
}
|
|
258
|
+
|
|
252
259
|
/**
|
|
253
260
|
* @experimental to be removed after transformMap2 is stable
|
|
254
261
|
*/
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { Transform } from 'node:stream'
|
|
2
|
+
import { _mb } from '@naturalcycles/js-lib'
|
|
3
|
+
import { _ms, localTime } from '@naturalcycles/js-lib/datetime'
|
|
4
|
+
import { createCommonLoggerAtLevel } from '@naturalcycles/js-lib/log'
|
|
5
|
+
import type { DeferredPromise } from '@naturalcycles/js-lib/promise'
|
|
6
|
+
import { pDefer } from '@naturalcycles/js-lib/promise/pDefer.js'
|
|
7
|
+
import type { Integer, NumberOfMilliseconds } from '@naturalcycles/js-lib/types'
|
|
8
|
+
import type { TransformOptions, TransformTyped } from '../stream.model.js'
|
|
9
|
+
|
|
10
|
+
export interface TransformThrottleByRSSOptions extends TransformOptions {
|
|
11
|
+
/**
|
|
12
|
+
* Maximum RSS (Resident Set Size) in megabytes.
|
|
13
|
+
* When process RSS exceeds this value, the stream will pause
|
|
14
|
+
* until RSS drops below the threshold.
|
|
15
|
+
*/
|
|
16
|
+
maxRSS: Integer
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* How often to re-check RSS (in milliseconds) while paused.
|
|
20
|
+
*
|
|
21
|
+
* @default 5000
|
|
22
|
+
*/
|
|
23
|
+
pollInterval?: NumberOfMilliseconds
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* If this timeout is reached while RSS is above the limit -
|
|
27
|
+
* the transform will "give up", log the bold warning, and "open the gateways".
|
|
28
|
+
* Things will likely OOM after that, but at least it will not "hang forever".
|
|
29
|
+
*
|
|
30
|
+
* @default 30 minutes
|
|
31
|
+
*/
|
|
32
|
+
pollTimeout?: NumberOfMilliseconds
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* What to do if pollTimeout is reached.
|
|
36
|
+
* 'open-the-floodgates' will disable this throttle completely (YOLO).
|
|
37
|
+
* 'throw' will throw an error, which will destroy the stream/Pipeline.
|
|
38
|
+
*
|
|
39
|
+
* @default 'open-the-floodgates'
|
|
40
|
+
*/
|
|
41
|
+
onPollTimeout?: 'open-the-floodgates' | 'throw'
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Throttles the stream based on process memory (RSS) usage.
|
|
46
|
+
* When RSS exceeds `maxRSS` (in megabytes), the stream pauses
|
|
47
|
+
* and periodically re-checks until RSS drops below the threshold.
|
|
48
|
+
*
|
|
49
|
+
* Useful for pipelines that process large amounts of data and
|
|
50
|
+
* may cause memory pressure (e.g. database imports, file processing).
|
|
51
|
+
*
|
|
52
|
+
* @experimental
|
|
53
|
+
*/
|
|
54
|
+
export function transformThrottleByRSS<T>(
|
|
55
|
+
opt: TransformThrottleByRSSOptions,
|
|
56
|
+
): TransformTyped<T, T> {
|
|
57
|
+
const {
|
|
58
|
+
maxRSS,
|
|
59
|
+
pollInterval = 5000,
|
|
60
|
+
pollTimeout = 30 * 60_000, // 30 min
|
|
61
|
+
onPollTimeout = 'open-the-floodgates',
|
|
62
|
+
objectMode = true,
|
|
63
|
+
highWaterMark,
|
|
64
|
+
} = opt
|
|
65
|
+
|
|
66
|
+
const maxRSSBytes = maxRSS * 1024 * 1024
|
|
67
|
+
let lock: DeferredPromise | undefined
|
|
68
|
+
let pollTimer: NodeJS.Timeout | undefined
|
|
69
|
+
let rssCheckTimer: NodeJS.Timeout | undefined
|
|
70
|
+
let lastRSS = 0
|
|
71
|
+
let pausedSince = 0
|
|
72
|
+
let disabled = false
|
|
73
|
+
const logger = createCommonLoggerAtLevel(opt.logger, opt.logLevel)
|
|
74
|
+
|
|
75
|
+
return new Transform({
|
|
76
|
+
objectMode,
|
|
77
|
+
highWaterMark,
|
|
78
|
+
async transform(item: T, _, cb) {
|
|
79
|
+
if (lock) {
|
|
80
|
+
try {
|
|
81
|
+
await lock
|
|
82
|
+
} catch (err) {
|
|
83
|
+
cb(err as Error)
|
|
84
|
+
return
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (!disabled && lastRSS > maxRSSBytes && !lock) {
|
|
89
|
+
lock = pDefer()
|
|
90
|
+
pausedSince = Date.now()
|
|
91
|
+
logger.log(
|
|
92
|
+
`${localTime.now().toPretty()} transformThrottleByRSS paused: RSS ${_mb(lastRSS)} > ${maxRSS} MB`,
|
|
93
|
+
)
|
|
94
|
+
pollTimer = setTimeout(() => pollRSS(), pollInterval)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
cb(null, item)
|
|
98
|
+
},
|
|
99
|
+
construct(cb) {
|
|
100
|
+
// Start periodic RSS checking
|
|
101
|
+
checkRSS()
|
|
102
|
+
cb()
|
|
103
|
+
},
|
|
104
|
+
final(cb) {
|
|
105
|
+
clearTimeout(pollTimer)
|
|
106
|
+
clearTimeout(rssCheckTimer)
|
|
107
|
+
cb()
|
|
108
|
+
},
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
function checkRSS(): void {
|
|
112
|
+
lastRSS = process.memoryUsage.rss()
|
|
113
|
+
rssCheckTimer = setTimeout(() => checkRSS(), pollInterval)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function pollRSS(): void {
|
|
117
|
+
const rss = lastRSS
|
|
118
|
+
|
|
119
|
+
if (rss <= maxRSSBytes) {
|
|
120
|
+
logger.log(
|
|
121
|
+
`${localTime.now().toPretty()} transformThrottleByRSS resumed: RSS ${_mb(rss)} <= ${maxRSS} MB`,
|
|
122
|
+
)
|
|
123
|
+
lock!.resolve()
|
|
124
|
+
lock = undefined
|
|
125
|
+
} else if (pollTimeout && Date.now() - pausedSince >= pollTimeout) {
|
|
126
|
+
clearTimeout(rssCheckTimer)
|
|
127
|
+
if (onPollTimeout === 'throw') {
|
|
128
|
+
lock!.reject(
|
|
129
|
+
new Error(
|
|
130
|
+
`transformThrottleByRSS pollTimeout of ${_ms(pollTimeout)} reached, RSS ${_mb(rss)} still > ${maxRSS} MB`,
|
|
131
|
+
),
|
|
132
|
+
)
|
|
133
|
+
lock = undefined
|
|
134
|
+
} else {
|
|
135
|
+
// open-the-floodgates
|
|
136
|
+
logger.error(
|
|
137
|
+
`${localTime.now().toPretty()} transformThrottleByRSS: pollTimeout of ${_ms(pollTimeout)} reached, RSS ${_mb(rss)} still > ${maxRSS} MB — DISABLING THROTTLE`,
|
|
138
|
+
)
|
|
139
|
+
disabled = true
|
|
140
|
+
lock!.resolve()
|
|
141
|
+
lock = undefined
|
|
142
|
+
}
|
|
143
|
+
} else {
|
|
144
|
+
logger.log(
|
|
145
|
+
`${localTime.now().toPretty()} transformThrottleByRSS still paused: RSS ${_mb(rss)} > ${maxRSS} MB, rechecking in ${_ms(pollInterval)}`,
|
|
146
|
+
)
|
|
147
|
+
pollTimer = setTimeout(() => pollRSS(), pollInterval)
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|