multi-tasks 3.1.1 → 3.1.3
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/README.md +30 -36
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# multi-tasks
|
|
2
2
|
|
|
3
|
-
Multi-tasks is a toolkit to manage long-term and large-scale parallel computing tasks.
|
|
3
|
+
Multi-tasks is a toolkit to manage long-term and large-scale parallel computing tasks. Progress and tasks are stored on the file system, so tasks can be resumed even if the host crashes.
|
|
4
4
|
|
|
5
5
|
**Zero dependencies:** multi-tasks has no runtime dependencies at all — it is built entirely on Node.js built-in modules (`cluster`, `fs`, `path`, `os`), so installing it adds nothing extra to your `node_modules`.
|
|
6
6
|
|
|
@@ -31,10 +31,10 @@ The API has three parts: the entry functions, the config options, and the `helpe
|
|
|
31
31
|
- **`numberOfWorkers`** — how many worker processes run in parallel; a number, or a percentage string of CPU cores like `"50%"` (default).
|
|
32
32
|
- **`taskTimeout`** — optional, milliseconds; an overdue task fails with a timeout error.
|
|
33
33
|
- **`maxTaskRetries`** — optional, max times a failed task is auto-retried.
|
|
34
|
-
- **`autoCloseAfterCompletion`** — set `
|
|
34
|
+
- **`autoCloseAfterCompletion`** — set `true` to kill workers and exit the process when no tasks are left; default is `false`, i.e. workers stay alive waiting for dynamically created tasks.
|
|
35
35
|
- **`shouldTerminate(info)`** — return `true` to terminate the whole process.
|
|
36
36
|
- **`setSysListener(event, payload, meta)`** — optional, handle custom system events (sent via `helper.emitSys`) on the master; `meta` has `fromWorkerId` and `fromWorkerPid`.
|
|
37
|
-
- **`onFinish(report)`** — called once after all workers
|
|
37
|
+
- **`onFinish(report)`** — called once after all workers exit (only when `autoCloseAfterCompletion` is `true`); `report` is an empty object for now.
|
|
38
38
|
|
|
39
39
|
**Task helper** (the `helper` object passed as the second argument of `processTask`):
|
|
40
40
|
|
|
@@ -49,7 +49,7 @@ The API has three parts: the entry functions, the config options, and the `helpe
|
|
|
49
49
|
//see examples/example0
|
|
50
50
|
let multiTasks = require('multi-tasks').multiTasks;
|
|
51
51
|
|
|
52
|
-
//Step1, create
|
|
52
|
+
//Step1, create the tasks to run in parallel as an array.
|
|
53
53
|
let alltasks = [];
|
|
54
54
|
for(let i=0;i<50;i++){
|
|
55
55
|
alltasks.push({
|
|
@@ -58,7 +58,7 @@ for(let i=0;i<50;i++){
|
|
|
58
58
|
});
|
|
59
59
|
};
|
|
60
60
|
|
|
61
|
-
//Step2, provide a function
|
|
61
|
+
//Step2, provide a function that processes each sub-task and returns the result
|
|
62
62
|
let processTask = (task, helper)=>{
|
|
63
63
|
let {taskCount} = task;//get your task data
|
|
64
64
|
|
|
@@ -72,12 +72,12 @@ let processTask = (task, helper)=>{
|
|
|
72
72
|
multiTasks({
|
|
73
73
|
initialTasks: alltasks,
|
|
74
74
|
processTask,
|
|
75
|
-
taskRootFolder: `../examples-tmp-data/example0`, //a directory to store progress and
|
|
75
|
+
taskRootFolder: `../examples-tmp-data/example0`, //a directory to store progress and result files; you can check the progress here
|
|
76
76
|
taskId: 'my-task',
|
|
77
77
|
numberOfWorkers: 3, //how many workers are working in parallel
|
|
78
78
|
//taskTimeout: 30000, //optional, in milliseconds, an overdue task is treated as failed with a timeout error
|
|
79
79
|
//maxTaskRetries: 2, //optional, auto-retry a failed task (worker crash, processTask error, or timeout); retried tasks go back to the queue
|
|
80
|
-
//autoCloseAfterCompletion: true, //
|
|
80
|
+
//autoCloseAfterCompletion: true, //set true to exit the process when all tasks are done; keep it false (default) if you create new tasks dynamically
|
|
81
81
|
shouldTerminate:(info)=>{
|
|
82
82
|
//return true if you need to terminate the whole process
|
|
83
83
|
},
|
|
@@ -91,6 +91,8 @@ multiTasks({
|
|
|
91
91
|
### More about the task processing function
|
|
92
92
|
|
|
93
93
|
```javascript
|
|
94
|
+
//Examples 1-3 below are independent variants of processTask, use one at a time.
|
|
95
|
+
|
|
94
96
|
//Example1, return a promise for async processes,
|
|
95
97
|
// you can return a promise or a non-promise result,
|
|
96
98
|
// all result data can be found in the results/succ folder
|
|
@@ -127,21 +129,26 @@ let processTask = (task, helper)=>{
|
|
|
127
129
|
let processTask = (task, helper)=>{
|
|
128
130
|
let {taskCount} = task;
|
|
129
131
|
|
|
130
|
-
//
|
|
132
|
+
//Demo of exceptions/errors: they are captured and saved in the results/errors folder
|
|
131
133
|
if(taskCount===3) throw 'exception';
|
|
132
134
|
if(taskCount===4) return Promise.reject({err:'a test error'});//use Promise.reject method
|
|
133
|
-
if(taskCount===5) aaa = bbb;//this
|
|
135
|
+
if(taskCount===5) aaa = bbb;//this ReferenceError will be captured by multi-tasks
|
|
134
136
|
|
|
135
137
|
return {data:'succ'};
|
|
136
138
|
}
|
|
137
139
|
|
|
138
|
-
//
|
|
139
|
-
//
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
140
|
+
//Example4, timeout: a task that does not finish within taskTimeout is
|
|
141
|
+
// treated as failed with a timeout error
|
|
142
|
+
multiTasks({
|
|
143
|
+
initialTasks: alltasks,
|
|
144
|
+
processTask,
|
|
145
|
+
taskRootFolder: `../examples-tmp-data/example-timeout`,
|
|
146
|
+
taskId: 'my-task',
|
|
147
|
+
numberOfWorkers: 3,
|
|
148
|
+
taskTimeout: 30000,
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
//Example5, auto-retry a failed task with maxTaskRetries
|
|
145
152
|
multiTasks({
|
|
146
153
|
initialTasks: alltasks,
|
|
147
154
|
processTask,
|
|
@@ -151,13 +158,7 @@ multiTasks({
|
|
|
151
158
|
maxTaskRetries: 2,
|
|
152
159
|
});
|
|
153
160
|
|
|
154
|
-
//Example6, broadcast events between workers
|
|
155
|
-
// a worker emits an event and the master relays it to every worker
|
|
156
|
-
// (best-effort, runtime only - not persisted, not replayed on
|
|
157
|
-
// resume); by default the sender also receives its own event, pass
|
|
158
|
-
// {includingMe: false} to exclude it; each event keeps only one
|
|
159
|
-
// listener per worker process, so calling setListener on every
|
|
160
|
-
// task is safe
|
|
161
|
+
//Example6, broadcast events between workers with helper.emit/helper.setListener
|
|
161
162
|
multiTasks({
|
|
162
163
|
initialTasks: alltasks,
|
|
163
164
|
taskRootFolder: `../examples-tmp-data/example-broadcast`,
|
|
@@ -172,12 +173,7 @@ multiTasks({
|
|
|
172
173
|
},
|
|
173
174
|
});
|
|
174
175
|
|
|
175
|
-
//Example7, system events from a worker to the master
|
|
176
|
-
// helper.emitSys sends a system event that the master consumes
|
|
177
|
-
// itself (not relayed to workers); the built-in event
|
|
178
|
-
// TERMINATE_ALL_WORKERS force-kills all workers and exits the
|
|
179
|
-
// master (unfinished tasks stay for resume); any other event is
|
|
180
|
-
// passed to config.setSysListener on the master
|
|
176
|
+
//Example7, system events from a worker to the master with helper.emitSys
|
|
181
177
|
multiTasks({
|
|
182
178
|
initialTasks: alltasks,
|
|
183
179
|
taskRootFolder: `../examples-tmp-data/example-sysevent`,
|
|
@@ -200,12 +196,12 @@ multiTasks({
|
|
|
200
196
|
|
|
201
197
|
### Resuming
|
|
202
198
|
|
|
203
|
-
|
|
199
|
+
If the execution is interrupted (e.g. a power outage), resume it like this:
|
|
204
200
|
|
|
205
201
|
```javascript
|
|
206
202
|
|
|
207
203
|
multiTasks({
|
|
208
|
-
initialTasks: `/myworks/my_scan_tasks/`, //
|
|
204
|
+
initialTasks: `/myworks/my_scan_tasks/`, //point 'initialTasks' to the interrupted task directory; multi-tasks reads the tasks in its 'new' folder and continues execution
|
|
209
205
|
...
|
|
210
206
|
...//Other configurations remain unchanged
|
|
211
207
|
...
|
|
@@ -213,12 +209,10 @@ multiTasks({
|
|
|
213
209
|
|
|
214
210
|
```
|
|
215
211
|
|
|
216
|
-
### Testing:
|
|
217
|
-
|
|
218
|
-
The usage patterns documented above are covered by automated tests (unit tests in `test/`, end-to-end tests in `teste2e/`). The e2e suite runs the API in real child processes with a mixed workload — successful tasks (both promise and non-promise results), planned failures (rejected promises and thrown exceptions), dynamically created tasks via `helper.createNewTasks`, and workers that crash randomly — then resumes repeatedly and verifies that every task lands exactly one result in `results/succ` or `results/errors`.
|
|
219
|
-
|
|
220
212
|
### Changelog:
|
|
221
213
|
|
|
214
|
+
- 3.1.3 Update README
|
|
215
|
+
- 3.1.2 Update README
|
|
222
216
|
- 3.1.1 Fix readme documentation
|
|
223
217
|
- 3.1.0 Support worker broadcast ('helper.emit' and 'helper.setListener') and system events ('helper.emitSys' and 'setSysListener', with built-in 'TERMINATE_ALL_WORKERS'); default numberOfWorkers is now "50%" of CPU cores (was core count minus 1)
|
|
224
218
|
- 3.0.4 numberOfWorkers accepts a percentage string of CPU cores, e.g. "50%"
|
|
@@ -263,4 +257,4 @@ The usage patterns documented above are covered by automated tests (unit tests i
|
|
|
263
257
|
|
|
264
258
|
### License:
|
|
265
259
|
|
|
266
|
-
[MIT](https://opensource.org/license/MIT)
|
|
260
|
+
[MIT](https://opensource.org/license/MIT)
|