batch-cluster
Advanced tools
Comparing version 4.0.0 to 4.1.0
@@ -20,4 +20,14 @@ # Changelog | ||
## v4.0.0 (not yet released) | ||
## v4.1.0 | ||
- ✨ Support for demoting task errors from `stderr` emissions: | ||
`BatchProcess.rejectTaskOnStderr` is a per-task, per-error predicate which | ||
allows for a given error to be handled without always rejecting the task. This | ||
can be handy if the script you're wrapping (like ExifTool) writes non-fatal | ||
warnings to stderr. | ||
- ✨ `BatchProcessOptions.pass` and `BatchProcessOptions.fail` can be RegExp | ||
instances now, if you have more exotic parsing needs. | ||
## v4.0.0 | ||
- 💔 Using Node 8+ to determine if a process is running with `kill(pid, 0)` | ||
@@ -24,0 +34,0 @@ turns out to be unreliable (as it returns true even after the process exits). |
@@ -31,13 +31,13 @@ /// <reference types="node" /> | ||
*/ | ||
readonly versionCommand: string; | ||
versionCommand: string; | ||
/** | ||
* Expected text to print if a command passes. Cannot be blank. Will be | ||
* interpreted as a regular expression fragment. | ||
* Expected text to print if a command passes. Cannot be blank. Strings will | ||
* be interpreted as a regular expression fragment. | ||
*/ | ||
readonly pass: string; | ||
pass: string | RegExp; | ||
/** | ||
* Expected text to print if a command fails. Cannot be blank. Will be | ||
* Expected text to print if a command fails. Cannot be blank. Strings will be | ||
* interpreted as a regular expression fragment. | ||
*/ | ||
readonly fail: string; | ||
fail: string | RegExp; | ||
/** | ||
@@ -49,3 +49,3 @@ * Command to end the child batch process. If not provided, stdin will be | ||
*/ | ||
readonly exitCommand?: string; | ||
exitCommand?: string; | ||
} | ||
@@ -134,2 +134,10 @@ /** | ||
readonly endGracefulWaitTimeMillis: number; | ||
/** | ||
* Some tools emit non-fatal warnings to stderr. If this predicate returns | ||
* false, the task will not be rejected. | ||
* | ||
* This defaults to a function that always returns true, which makes all | ||
* stderr writes reject tasks. | ||
*/ | ||
readonly rejectTaskOnStderr: (task: Task<any>, error: string | Error) => boolean; | ||
} | ||
@@ -183,3 +191,14 @@ /** | ||
readonly ended: boolean; | ||
/** | ||
* Shut down this instance, and all child processes. | ||
* @param gracefully should an attempt be made to finish in-flight tasks, or | ||
* should we force-kill child PIDs. | ||
*/ | ||
end(gracefully?: boolean): Promise<void>; | ||
/** | ||
* Submits `task` for processing by a `BatchProcess` instance | ||
* | ||
* @return a Promise that is resolved or rejected once the task has been | ||
* attemped on an idle BatchProcess | ||
*/ | ||
enqueueTask<T>(task: Task<T>): Promise<T>; | ||
@@ -186,0 +205,0 @@ /** |
@@ -154,2 +154,10 @@ "use strict"; | ||
this.endGracefulWaitTimeMillis = 500; | ||
/** | ||
* Some tools emit non-fatal warnings to stderr. If this predicate returns | ||
* false, the task will not be rejected. | ||
* | ||
* This defaults to a function that always returns true, which makes all | ||
* stderr writes reject tasks. | ||
*/ | ||
this.rejectTaskOnStderr = function () { return true; }; | ||
} | ||
@@ -161,3 +169,5 @@ return BatchClusterOptions; | ||
function toRe(s) { | ||
return new RegExp("^([\\s\\S]*?)[\\n\\r]+" + s + "[\\n\\r]*$"); | ||
return s instanceof RegExp | ||
? s | ||
: new RegExp("^((?:[\\s\\S]*[\\n\\r]+)?)" + s + "[\\n\\r]*$"); | ||
} | ||
@@ -289,3 +299,4 @@ var result = __assign({}, new BatchClusterOptions(), opts, { passRE: toRe(opts.pass), failRE: toRe(opts.fail) }); | ||
onTaskError: function (err, task) { return _this.emitter.emit("taskError", err, task); }, | ||
onInternalError: function (err) { return _this.onInternalError(err); } | ||
onInternalError: function (err) { return _this.onInternalError(err); }, | ||
rejectTaskOnStderr: this.opts.rejectTaskOnStderr | ||
}; | ||
@@ -305,2 +316,7 @@ _p.once("beforeExit", this.beforeExitListener); | ||
}); | ||
/** | ||
* Shut down this instance, and all child processes. | ||
* @param gracefully should an attempt be made to finish in-flight tasks, or | ||
* should we force-kill child PIDs. | ||
*/ | ||
BatchCluster.prototype.end = function (gracefully) { | ||
@@ -341,2 +357,8 @@ if (gracefully === void 0) { gracefully = true; } | ||
}; | ||
/** | ||
* Submits `task` for processing by a `BatchProcess` instance | ||
* | ||
* @return a Promise that is resolved or rejected once the task has been | ||
* attemped on an idle BatchProcess | ||
*/ | ||
BatchCluster.prototype.enqueueTask = function (task) { | ||
@@ -343,0 +365,0 @@ var _this = this; |
@@ -13,2 +13,3 @@ /// <reference types="node" /> | ||
onInternalError(error: Error): void; | ||
rejectTaskOnStderr: (task: Task<any>, error: string | Error) => boolean; | ||
} | ||
@@ -15,0 +16,0 @@ export interface InternalBatchProcessOptions extends BatchProcessOptions, BatchClusterOptions { |
@@ -307,3 +307,3 @@ "use strict"; | ||
return __awaiter(this, void 0, void 0, function () { | ||
var error; | ||
var error, fatal; | ||
return __generator(this, function (_a) { | ||
@@ -323,2 +323,11 @@ if (task == null) { | ||
} | ||
if (task != null) { | ||
fatal = source !== "stderr.data" || | ||
this.observer.rejectTaskOnStderr(task, error); | ||
if (!fatal) { | ||
BatchCluster_1.logger().info("Error permitted by observer, will continue with task."); | ||
this.onData(""); | ||
return [2 /*return*/]; | ||
} | ||
} | ||
// clear the task before ending so the onExit from end() doesn't retry the task: | ||
@@ -358,5 +367,7 @@ this.clearCurrentTask(); | ||
BatchProcess.prototype.onData = function (data) { | ||
BatchCluster_1.logger().trace(this.name + ".onData(" + data.toString() + ")"); | ||
this.buff = this.buff + data.toString(); | ||
var pass = this.opts.passRE.exec(this.buff); | ||
if (pass != null) { | ||
BatchCluster_1.logger().trace(this.name + " found PASS"); | ||
this.resolveCurrentTask(pass[1].trim()); | ||
@@ -368,2 +379,3 @@ this.observer.onIdle(); | ||
if (fail != null) { | ||
BatchCluster_1.logger().trace(this.name + " found FAIL"); | ||
var err = new Error(cleanError(fail[1]) || "command error"); | ||
@@ -370,0 +382,0 @@ this.onError("onData", err); |
{ | ||
"name": "batch-cluster", | ||
"version": "4.0.0", | ||
"version": "4.1.0", | ||
"description": "Manage a cluster of child processes", | ||
@@ -22,4 +22,4 @@ "main": "dist/BatchCluster.js", | ||
"test": "mocha --opts .mocha.opts", | ||
"predocs": "typedoc --name batch-cluster --out ./docs --readme ./README.md --exclude \"**/*+(test|spec).ts\" --excludePrivate --excludeProtected --theme minimal src", | ||
"docs": "echo batch-cluster.js.org > docs/CNAME && touch docs/.nojekyll && yarn serve docs" | ||
"predocs": "typedoc --options ./.typedoc.js", | ||
"docs": "echo batch-cluster.js.org > ./docs/CNAME && touch ./docs/.nojekyll && yarn serve docs" | ||
}, | ||
@@ -36,3 +36,3 @@ "author": "Matthew McEachen <matthew-batchcluster@mceachen.org>", | ||
"@types/mocha": "^5.2.5", | ||
"@types/node": "^10.7.0", | ||
"@types/node": "^10.7.1", | ||
"chai": "^4.1.2", | ||
@@ -49,3 +49,3 @@ "chai-as-promised": "^7.1.1", | ||
"timekeeper": "^2.1.2", | ||
"typedoc": "^0.11.1", | ||
"typedoc": "^0.12.0", | ||
"typescript": "^3.0.1", | ||
@@ -52,0 +52,0 @@ "wtfnode": "^0.7.0" |
@@ -27,3 +27,3 @@ # batch-cluster | ||
This package powers | ||
[exiftool-vendored](https://github.com/mceachen/exiftool-vendored.js), whose | ||
[exiftool-vendored](https://exiftool-vendored.js.org/), whose | ||
source you can examine as an example consumer. | ||
@@ -43,32 +43,33 @@ | ||
See [CHANGELOG.md](CHANGELOG.md). | ||
See [CHANGELOG.md](https://github.com/mceachen/batch-cluster.js/blob/master/CHANGELOG.md). | ||
## Usage | ||
_If links are broken, please read this on | ||
[batch-cluster.js.org](https://batch-cluster.js.org/)._ | ||
The child process must use `stdin` and `stdout` for control/response. | ||
BatchCluster will ensure a given process is only given one task at a time. | ||
_If these links are broken, use <https://batch-cluster.js.org/>_ | ||
1. Create a singleton instance of | ||
[BatchCluster](/classes/_batchcluster_.batchcluster.html). | ||
[BatchCluster](/classes/batchcluster.html). | ||
Note the [constructor | ||
options](/classes/_batchcluster_.batchcluster.html#constructor) takes a union | ||
options](/classes/batchcluster.html#constructor) takes a union | ||
type of | ||
- [ChildProcessFactory](/interfaces/_batchcluster_.childprocessfactory.html) and | ||
- [BatchProcessOptions](/interfaces/_batchcluster_.batchprocessoptions.html), | ||
- [ChildProcessFactory](/interfaces/childprocessfactory.html) and | ||
- [BatchProcessOptions](/interfaces/batchprocessoptions.html), | ||
both of which have no defaults, and | ||
- [BatchClusterOptions](/classes/_batchcluster_.batchclusteroptions.html), | ||
- [BatchClusterOptions](/classes/batchclusteroptions.html), | ||
which has defaults that may or may not be relevant to your application. | ||
1. The [default](/modules/_logger_.consolelogger.html) logger writes warning and | ||
1. The [default](/modules/logger.html) logger writes warning and | ||
error messages to `console.warn` and `console.error`. You can change this to | ||
your logger by using [setLogger](/modules/_logger_.html#setlogger). | ||
your logger by using [setLogger](/globals.html#setlogger). | ||
1. Implement the [Parser](/modules/_task_.html#parser) class to parse results from your child | ||
1. Implement the [Parser](/globals.html#parser) class to parse results from your child | ||
process. | ||
1. Construct a [Task](/classes/_task_.task.html) with the desired command and | ||
1. Construct a [Task](/classes/task.html) with the desired command and | ||
the parser you built in the previous step, and submit it to your BatchCluster | ||
@@ -75,0 +76,0 @@ singleton's |
Sorry, the diff of this file is not supported yet
172234
2049
81