template-project/node_modules/batch-cluster/dist/BatchClusterOptions.js
2025-05-30 18:13:30 +08:00

216 lines
8.8 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.verifyOptions = exports.BatchClusterOptions = exports.minuteMs = exports.secondMs = void 0;
const Logger_1 = require("./Logger");
const Platform_1 = require("./Platform");
const String_1 = require("./String");
exports.secondMs = 1000;
exports.minuteMs = 60 * exports.secondMs;
/**
* These parameter values have somewhat sensible defaults, but can be
* overridden for a given BatchCluster.
*/
class BatchClusterOptions {
constructor() {
/**
* No more than `maxProcs` child processes will be run at a given time
* to serve pending tasks.
*
* Defaults to 1.
*/
this.maxProcs = 1;
/**
* Child processes will be recycled when they reach this age.
*
* This value must not be less than `spawnTimeoutMillis` or
* `taskTimeoutMillis`.
*
* Defaults to 5 minutes. Set to 0 to disable.
*/
this.maxProcAgeMillis = 5 * exports.minuteMs;
/**
* This is the minimum interval between calls to BatchCluster's #onIdle
* method, which runs general janitorial processes like child process
* management and task queue validation.
*
* Must be > 0. Defaults to 10 seconds.
*/
this.onIdleIntervalMillis = 10 * exports.secondMs;
/**
* If the initial `versionCommand` fails for new spawned processes more
* than this rate, end this BatchCluster and throw an error, because
* something is terribly wrong.
*
* If this backstop didn't exist, new (failing) child processes would be
* created indefinitely.
*
* Defaults to 10. Set to 0 to disable.
*/
this.maxReasonableProcessFailuresPerMinute = 10;
/**
* Spawning new child processes and servicing a "version" task must not take
* longer than `spawnTimeoutMillis` before the process is considered failed,
* and need to be restarted. Be pessimistic here--windows can regularly take
* several seconds to spin up a process, thanks to antivirus shenanigans.
*
* Defaults to 15 seconds. Set to 0 to disable.
*/
this.spawnTimeoutMillis = 15 * exports.secondMs;
/**
* If maxProcs > 1, spawning new child processes to process tasks can slow
* down initial processing, and create unnecessary processes.
*
* Must be >= 0ms. Defaults to 1.5 seconds.
*/
this.minDelayBetweenSpawnMillis = 1.5 * exports.secondMs;
/**
* If commands take longer than this, presume the underlying process is dead
* and we should fail the task.
*
* This should be set to something on the order of seconds.
*
* Defaults to 10 seconds. Set to 0 to disable.
*/
this.taskTimeoutMillis = 10 * exports.secondMs;
/**
* Processes will be recycled after processing `maxTasksPerProcess` tasks.
* Depending on the commands and platform, batch mode commands shouldn't
* exhibit unduly memory leaks for at least tens if not hundreds of tasks.
* Setting this to a low number (like less than 10) will impact performance
* markedly, due to OS process start/stop maintenance. Setting this to a very
* high number (> 1000) may result in more memory being consumed than
* necessary.
*
* Must be >= 0. Defaults to 500
*/
this.maxTasksPerProcess = 500;
/**
* When `this.end()` is called, or Node broadcasts the `beforeExit` event,
* this is the milliseconds spent waiting for currently running tasks to
* finish before sending kill signals to child processes.
*
* Setting this value to 0 means child processes will immediately receive a
* kill signal to shut down. Any pending requests may be interrupted. Must be
* >= 0. Defaults to 500ms.
*/
this.endGracefulWaitTimeMillis = 500;
/**
* When a task sees a "pass" or "fail" from either stdout or stderr, it needs
* to wait for the other stream to finish flushing to ensure the task's Parser
* sees the entire relevant stream contents. A larger number may be required
* for slower computers to prevent internal errors due to lack of stream
* coercion.
*
* Note that this puts a hard lower limit on task latency, so don't set this
* to a large number: no task will resolve faster than this value (in millis).
*
* If you set this value too low, tasks may be erroneously resolved or
* rejected (depending on which stream is handled first).
*
* Your system may support a smaller value: this is a pessimistic default. If
* this is set too low, you'll see `noTaskData` events.
*
* Setting this to 0 makes whatever flushes first--stdout and stderr--and will
* most likely result in internal errors (due to stream buffers not being able
* to be associated to tasks that were just settled)
*/
// These values were found by trial and error using GitHub CI boxes, which
// should be the bottom of the barrel, performance-wise, of any computer.
this.streamFlushMillis = Platform_1.isMac ? 100 : Platform_1.isWin ? 200 : 30;
/**
* Should batch-cluster try to clean up after spawned processes that don't
* shut down?
*
* Only disable this if you have another means of PID cleanup.
*
* Defaults to `true`.
*/
this.cleanupChildProcs = true;
/**
* If a child process is idle for more than this value (in milliseconds), shut
* it down to reduce system resource consumption.
*
* A value of ~10 seconds to a couple minutes would be reasonable. Set this to
* 0 to disable this feature.
*/
this.maxIdleMsPerProcess = 0;
/**
* How many failed tasks should a process be allowed to process before it is
* recycled?
*
* Set this to 0 to disable this feature.
*/
this.maxFailedTasksPerProcess = 2;
/**
* If `healthCheckCommand` is set, how frequently should we check for
* unhealthy child processes?
*
* Set this to 0 to disable this feature.
*/
this.healthCheckIntervalMillis = 0;
/**
* Verify child processes are still running by checking the OS process table.
*
* Set this to 0 to disable this feature.
*/
this.pidCheckIntervalMillis = 2 * exports.minuteMs;
/**
* A BatchCluster instance and associated BatchProcess instances will share
* this `Logger`. Defaults to the `Logger` instance provided to `setLogger()`.
*/
this.logger = Logger_1.logger;
}
}
exports.BatchClusterOptions = BatchClusterOptions;
function escapeRegExp(s) {
return (0, String_1.toS)(s).replace(/[-.,\\^$*+?()|[\]{}]/g, "\\$&");
}
function toRe(s) {
return s instanceof RegExp
? s
: new RegExp("(?:\\n|^)" + escapeRegExp(s) + "(?:\\r?\\n|$)");
}
function verifyOptions(opts) {
const result = {
...new BatchClusterOptions(),
...opts,
passRE: toRe(opts.pass),
failRE: toRe(opts.fail),
};
const errors = [];
function notBlank(fieldName) {
const v = (0, String_1.toS)(result[fieldName]);
if ((0, String_1.blank)(v)) {
errors.push(fieldName + " must not be blank");
}
}
function gte(fieldName, value, why) {
const v = result[fieldName];
if (v < value) {
const msg = `${fieldName} must be greater than or equal to ${value}${(0, String_1.blank)(why) ? "" : ": " + why}`;
errors.push(msg);
}
}
notBlank("versionCommand");
notBlank("pass");
notBlank("fail");
gte("maxTasksPerProcess", 1);
gte("maxProcs", 1);
if (opts.maxProcAgeMillis != null &&
opts.maxProcAgeMillis > 0 &&
result.taskTimeoutMillis) {
gte("maxProcAgeMillis", Math.max(result.spawnTimeoutMillis, result.taskTimeoutMillis), `the max value of spawnTimeoutMillis (${result.spawnTimeoutMillis}) and taskTimeoutMillis (${result.taskTimeoutMillis})`);
}
// 0 disables:
gte("minDelayBetweenSpawnMillis", 0);
gte("onIdleIntervalMillis", 0);
gte("endGracefulWaitTimeMillis", 0);
gte("maxReasonableProcessFailuresPerMinute", 0);
gte("streamFlushMillis", 0);
if (errors.length > 0) {
throw new Error("BatchCluster was given invalid options: " + errors.join("; "));
}
return result;
}
exports.verifyOptions = verifyOptions;
//# sourceMappingURL=BatchClusterOptions.js.map