batch-cluster
Version:
Manage a cluster of child processes
158 lines • 8.3 kB
JavaScript
"use strict";
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var _Task_instances, _Task_opts, _Task_startedAt, _Task_parsing, _Task_settledAt, _Task_d, _Task_stdout, _Task_stderr, _Task_onSettle, _Task_resolve;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Task = void 0;
const Async_1 = require("./Async");
const Deferred_1 = require("./Deferred");
let _taskId = 1;
/**
* Tasks embody individual jobs given to the underlying child processes. Each
* instance has a promise that will be resolved or rejected based on the
* result of the task.
*/
class Task {
/**
* @param {string} command is the value written to stdin to perform the given
* task.
* @param {Parser<T>} parser is used to parse resulting data from the
* underlying process to a typed object.
*/
constructor(command, parser) {
_Task_instances.add(this);
this.command = command;
this.parser = parser;
this.taskId = _taskId++;
_Task_opts.set(this, void 0);
_Task_startedAt.set(this, void 0);
_Task_parsing.set(this, false);
_Task_settledAt.set(this, void 0);
_Task_d.set(this, new Deferred_1.Deferred());
_Task_stdout.set(this, "");
_Task_stderr.set(this, ""
/**
* @param {string} command is the value written to stdin to perform the given
* task.
* @param {Parser<T>} parser is used to parse resulting data from the
* underlying process to a typed object.
*/
);
// We can't use .finally here, because that creates a promise chain that, if
// rejected, results in an uncaught rejection.
__classPrivateFieldGet(this, _Task_d, "f").promise.then(() => __classPrivateFieldGet(this, _Task_instances, "m", _Task_onSettle).call(this), () => __classPrivateFieldGet(this, _Task_instances, "m", _Task_onSettle).call(this));
}
/**
* @return the resolution or rejection of this task.
*/
get promise() {
return __classPrivateFieldGet(this, _Task_d, "f").promise;
}
get pending() {
return __classPrivateFieldGet(this, _Task_d, "f").pending;
}
get state() {
return __classPrivateFieldGet(this, _Task_d, "f").pending
? "pending"
: __classPrivateFieldGet(this, _Task_d, "f").rejected
? "rejected"
: "resolved";
}
onStart(opts) {
__classPrivateFieldSet(this, _Task_opts, opts, "f");
__classPrivateFieldSet(this, _Task_startedAt, Date.now(), "f");
}
get runtimeMs() {
var _a;
return __classPrivateFieldGet(this, _Task_startedAt, "f") == null
? undefined
: ((_a = __classPrivateFieldGet(this, _Task_settledAt, "f")) !== null && _a !== void 0 ? _a : Date.now()) - __classPrivateFieldGet(this, _Task_startedAt, "f");
}
toString() {
return (this.constructor.name +
"(" +
this.command.replace(/\s+/gm, " ").slice(0, 80).trim() +
")#" +
this.taskId);
}
onStdout(buf) {
var _a, _b;
__classPrivateFieldSet(this, _Task_stdout, __classPrivateFieldGet(this, _Task_stdout, "f") + buf.toString(), "f");
const passRE = (_a = __classPrivateFieldGet(this, _Task_opts, "f")) === null || _a === void 0 ? void 0 : _a.passRE;
if (passRE != null && passRE.exec(__classPrivateFieldGet(this, _Task_stdout, "f")) != null) {
// remove the pass token from stdout:
__classPrivateFieldSet(this, _Task_stdout, __classPrivateFieldGet(this, _Task_stdout, "f").replace(passRE, ""), "f");
void __classPrivateFieldGet(this, _Task_instances, "m", _Task_resolve).call(this, true);
}
else {
const failRE = (_b = __classPrivateFieldGet(this, _Task_opts, "f")) === null || _b === void 0 ? void 0 : _b.failRE;
if (failRE != null && failRE.exec(__classPrivateFieldGet(this, _Task_stdout, "f")) != null) {
// remove the fail token from stdout:
__classPrivateFieldSet(this, _Task_stdout, __classPrivateFieldGet(this, _Task_stdout, "f").replace(failRE, ""), "f");
void __classPrivateFieldGet(this, _Task_instances, "m", _Task_resolve).call(this, false);
}
}
}
onStderr(buf) {
var _a;
__classPrivateFieldSet(this, _Task_stderr, __classPrivateFieldGet(this, _Task_stderr, "f") + buf.toString(), "f");
const failRE = (_a = __classPrivateFieldGet(this, _Task_opts, "f")) === null || _a === void 0 ? void 0 : _a.failRE;
if (failRE != null && failRE.exec(__classPrivateFieldGet(this, _Task_stderr, "f")) != null) {
// remove the fail token from stderr:
__classPrivateFieldSet(this, _Task_stderr, __classPrivateFieldGet(this, _Task_stderr, "f").replace(failRE, ""), "f");
void __classPrivateFieldGet(this, _Task_instances, "m", _Task_resolve).call(this, false);
}
}
/**
* @return true if the wrapped promise was rejected
*/
reject(error) {
return __classPrivateFieldGet(this, _Task_d, "f").reject(error);
}
}
exports.Task = Task;
_Task_opts = new WeakMap(), _Task_startedAt = new WeakMap(), _Task_parsing = new WeakMap(), _Task_settledAt = new WeakMap(), _Task_d = new WeakMap(), _Task_stdout = new WeakMap(), _Task_stderr = new WeakMap(), _Task_instances = new WeakSet(), _Task_onSettle = function _Task_onSettle() {
var _a;
__classPrivateFieldSet(this, _Task_settledAt, (_a = __classPrivateFieldGet(this, _Task_settledAt, "f")) !== null && _a !== void 0 ? _a : Date.now(), "f");
}, _Task_resolve = async function _Task_resolve(passed) {
var _a, _b, _c;
// fail always wins.
passed = !__classPrivateFieldGet(this, _Task_d, "f").rejected && passed;
// wait for stderr and stdout to flush:
const flushMs = (_b = (_a = __classPrivateFieldGet(this, _Task_opts, "f")) === null || _a === void 0 ? void 0 : _a.streamFlushMillis) !== null && _b !== void 0 ? _b : 0;
if (flushMs > 0) {
await (0, Async_1.delay)(flushMs);
}
// we're expecting this method may be called concurrently (if there are both
// pass and fail tokens found in stderr and stdout), but we only want to run
// this once, so
if (!this.pending || __classPrivateFieldGet(this, _Task_parsing, "f"))
return;
// this.#opts
// ?.logger()
// .trace("Task.#resolve()", { command: this.command, state: this.state })
// Prevent concurrent parsing:
__classPrivateFieldSet(this, _Task_parsing, true, "f");
try {
const parseResult = await this.parser(__classPrivateFieldGet(this, _Task_stdout, "f"), __classPrivateFieldGet(this, _Task_stderr, "f"), passed);
if (__classPrivateFieldGet(this, _Task_d, "f").resolve(parseResult)) {
// success
}
else {
(_c = __classPrivateFieldGet(this, _Task_opts, "f")) === null || _c === void 0 ? void 0 : _c.observer.emit("internalError", new Error(this.toString() + " ._resolved() more than once"));
}
}
catch (error) {
this.reject(error instanceof Error ? error : new Error(String(error)));
}
};
//# sourceMappingURL=Task.js.map