216 lines
8.8 KiB
JavaScript
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
|