multi-tasks 1.2.0 → 1.2.1

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 CHANGED
@@ -14,7 +14,9 @@ How to use:
14
14
  let multiTasks = require('multi-tasks').multiTasks;
15
15
  multiTasks({
16
16
  tasks: [...], //You need to provide an array containing all the subtasks you want to execute, multi-tasks will automatically split them and execute them in a multi-threaded manner
17
- taskResolver:(task)=>{//You need to provide a taskResolver function to process a certain sub-task and return the result data
17
+ processTask:(task)=>{//You need to provide a processTask function to process a certain sub-task and return the result data
18
+ //process your task
19
+ let data = {...};
18
20
  return Promise.resolve(data);
19
21
  },
20
22
  multi_task_parent_folder: `C:/tmp-demo`, //a directory to store progress and results files
@@ -47,6 +49,7 @@ node examples/example1/run
47
49
 
48
50
  Changelog:
49
51
 
52
+ - 1.2.1 Handle exceptions and errors in subtasks
50
53
  - 1.2.0 Simplified usage by providing the function way and support return Promise
51
54
  - 1.1.4 Remove make-dir
52
55
  - 1.1.3 Simplified usage, see example0
@@ -56,3 +59,7 @@ Changelog:
56
59
  - 1.0.8 Fix examples
57
60
  - 1.0.7 Remove moment
58
61
  - 1.0.6 Performance optimization
62
+
63
+ Github:
64
+
65
+ [https://github.com/zhanglei923/multi-tasks](https://github.com/zhanglei923/multi-tasks)
@@ -1,7 +1,7 @@
1
1
  let multiTasks = require('../../index').multiTasks;
2
2
 
3
3
  let alltasks = []
4
- for(let i=0;i<200;i++){
4
+ for(let i=0;i<12;i++){
5
5
  let task_props = {
6
6
  index: i,
7
7
  name: `task-${i}`,
@@ -10,8 +10,11 @@ for(let i=0;i<200;i++){
10
10
  alltasks.push(task_props);
11
11
  }
12
12
 
13
- let taskResolver = (actionData)=>{
13
+ let processTask = (actionData)=>{
14
14
  console.log('this is the actionData of one task', actionData);
15
+ let {index} = actionData;
16
+ if(index===3) throw 'exception';
17
+ if(index===4) return Promise.reject({err:'a test error'});
15
18
  return Promise.resolve({
16
19
  message: 'this is a result from a demo, random data=' + Math.random()
17
20
  });
@@ -19,7 +22,7 @@ let taskResolver = (actionData)=>{
19
22
 
20
23
  multiTasks({
21
24
  tasks: alltasks, //You need to provide the data of all subtasks, multi-tasks will automatically split them and execute them in a multi-threaded manner
22
- taskResolver, //You need to provide a taskResolver function to process a certain sub-task and return the result data
25
+ processTask, //You need to provide a processTask function to process a certain sub-task and return the result data
23
26
  multi_task_parent_folder: `C:/tmp-demo`, //a directory to store progress and results files
24
27
  quotaOfEachTask:2, //The number of tasks assigned to each worker
25
28
  numberOfWorks: 6
@@ -2,9 +2,12 @@ let SuperConsumer = require('../../index').SuperConsumer;
2
2
 
3
3
  class TestConsumer extends SuperConsumer {
4
4
 
5
- process(actionData){
5
+ processTask(actionData){
6
6
  console.log(`processing data:`, actionData);
7
7
  //you can also return a data instead of a promise object
8
+ let {index} = actionData;
9
+ if(index===3) throw 'exception';
10
+ if(index===4) return Promise.reject({err:'a test error'});
8
11
  return new Promise((resolve) => {
9
12
  setTimeout(() => {
10
13
  let result = {
@@ -13,7 +13,7 @@ class TestProducer extends SuperProducer {
13
13
  /**
14
14
  * Generate all your tasks in this method, return as an array;
15
15
  * These data will be allocated to multiple threads (workers) for running;
16
- * You can obtain each of the data and process it in the 'process' method of your consumer.
16
+ * You can obtain each of the data and process it in the 'processTask' method of your consumer.
17
17
  *
18
18
  * **/
19
19
 
@@ -13,7 +13,7 @@ class TestProducer extends SuperProducer {
13
13
  /**
14
14
  * Generate all your tasks in this method, return as an array;
15
15
  * These data will be allocated to multiple threads (workers) for running;
16
- * You can obtain each of the data and process it in the 'process' method of your consumer.
16
+ * You can obtain each of the data and process it in the 'processTask' method of your consumer.
17
17
  *
18
18
  * **/
19
19
 
package/index.js CHANGED
@@ -5,8 +5,8 @@ const multiTasks = (config)=>{
5
5
  if(!config.tasks){
6
6
  throw 'Please provide tasks data';
7
7
  };
8
- if(!config.taskResolver){
9
- throw 'Please provide taskResolver function';
8
+ if(!config.processTask){
9
+ throw 'Please provide processTask function';
10
10
  };
11
11
  class TestProducer extends SuperProducer {
12
12
  // constructor
@@ -18,9 +18,9 @@ const multiTasks = (config)=>{
18
18
  }
19
19
  }
20
20
  class TestConsumer extends SuperConsumer {
21
- process(taskInfo, actionData){
22
- console.log(`processing data:`, taskInfo, actionData);
23
- let result = config.taskResolver(actionData);
21
+ processTask(taskProp){
22
+ console.log(`processing data:`, taskProp);
23
+ let result = config.processTask(taskProp);
24
24
  return Promise.resolve(result);
25
25
  }
26
26
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "multi-tasks",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "directories": {
@@ -12,38 +12,48 @@ class SuperConsumer {
12
12
  setTaskTrunkInfo(trunkInfo){
13
13
  this.trunkInfo = trunkInfo;
14
14
  }
15
- _run (mainTaskInfo, subTaskInfo, actions, results, callback){
15
+ _run (mainTaskInfo, subTaskInfo, actions, results, errors, callback){
16
16
  if(actions.length === 0) return callback({
17
17
  finishedAt: new Date()*1,
18
18
  results,
19
+ errors,
19
20
  subTaskInfo
20
21
  });
21
- let taskInfo = {
22
- mainid: this.mainid,
23
- subid: this.subid
24
- };
25
- let actionData = actions.shift();
22
+ let taskProp = actions.shift();
26
23
 
27
- if(this.process){
28
- let result = this.process(actionData);//rewrite this method in subclass
24
+ if(this.processTask){
25
+ let result;
26
+ let hasException = false;
27
+ try{
28
+ result = this.processTask(taskProp);//rewrite this method in subclass
29
+ }catch(e){
30
+ hasException = true;
31
+ result = {taskProp, exception: 'Exception:' + e.toString()}
32
+ }
29
33
  if(typeof result === 'undefined') result = {};
30
34
  let ispromise = result instanceof Promise;
31
- if(! ispromise){
32
- result = Promise.resolve(result);
33
- }
34
- result.then((data)=>{
35
- results.push(data);
36
- this._run(mainTaskInfo, subTaskInfo, actions, results, callback);
35
+ if(!ispromise){result = Promise.resolve(result);}
36
+ result.then((taskResult)=>{
37
+ if(!hasException){
38
+ results.push({taskProp, taskResult});
39
+ }else{
40
+ errors.push(taskResult);
41
+ }
42
+ }).catch((e)=>{
43
+ errors.push({taskProp, exception: 'Exception:' + e.toString()});
44
+ }).finally(()=>{
45
+ this._run(mainTaskInfo, subTaskInfo, actions, results, errors, callback);
37
46
  });
38
47
  }else{
39
- this._run(mainTaskInfo, subTaskInfo, actions, results, callback);
48
+ this._run(mainTaskInfo, subTaskInfo, actions, results, errors, callback);
40
49
  }
41
50
  };
42
51
  run (mainTaskInfo, subTaskInfo, taskInfo, callback){
43
52
  let results = [];
53
+ let errors = [];
44
54
  let actions = subTaskInfo.actions;
45
55
  mainTaskInfo.defination = this.trunkInfo.defination;
46
- this._run(mainTaskInfo, subTaskInfo, actions, results, (result)=>{
56
+ this._run(mainTaskInfo, subTaskInfo, actions, results, errors, (result)=>{
47
57
  callback(result)
48
58
  })
49
59
 
@@ -61,13 +71,18 @@ class SuperConsumer {
61
71
  let subid = subTaskInfo.subid;
62
72
  let taskfolderNew = mainTaskInfo.taskFolderNew;
63
73
  let taskFolderResult = mainTaskInfo.taskFolderResult;
74
+ let taskFolderResultFailed = mainTaskInfo.taskFolderResultFailed;
64
75
  this.mvTask(mainid, subid,'new','running', (taskFile)=>{//mark as running
65
76
  let taskContent = fs.readFileSync(taskFile, 'utf8');
66
77
  let taskInfo = JSON.parse(taskContent);
67
78
  this.run(mainTaskInfo, subTaskInfo, taskInfo, (taskReport)=>{//invoke
68
- let resultfile = pathutil.resolve(taskFolderResult, `${subid}.json`)
79
+ let {results, errors} = taskReport;
80
+ let hasError = false;
81
+ if(errors && errors.length > 0) hasError = true;
82
+ let folder = !hasError ? taskFolderResult : taskFolderResultFailed;
83
+ let resultfile = pathutil.resolve(folder, `${subid}.json`)
69
84
  fs.writeFileSync(resultfile, JSON.stringify(taskReport));
70
- this.mvTask(mainid, subid,'running','finished', ()=>{//mark as finished
85
+ this.mvTask(mainid, subid,'running',(hasError ? 'finished_with_errors':'finished'), ()=>{//mark as finished
71
86
  resolve({
72
87
  mainid,
73
88
  subid,
@@ -79,7 +94,7 @@ class SuperConsumer {
79
94
  });
80
95
  }
81
96
  mvTask (mainid, subid, from, to, callback) {
82
- let __thisdir = this.mainTaskInfo.taskFolder;
97
+ let __thisdir = this.mainTaskInfo.progressRootFolder;
83
98
  let oldPath = pathutil.resolve(__thisdir, `./${from}/${subid}.task.json`);
84
99
  let newPath = pathutil.resolve(__thisdir, `./${to}/${subid}.task.json`);
85
100
  fs.rename(oldPath, newPath, (err) => {
@@ -39,17 +39,25 @@ class SuperProducer {
39
39
  let taskFolder = this.taskfolder;
40
40
  //let taskfolder = pathutil.parse(__filename).dir;
41
41
  //let taskFolder = pathutil.resolve(taskfolder, `./tasks/${masterTaskId}`);
42
- let taskFolderNew = pathutil.resolve(taskFolder, './new');
43
- let taskFolderRunning = pathutil.resolve(taskFolder, './running');
44
- let taskFolderFinished = pathutil.resolve(taskFolder, './finished');
45
- let taskFolderResult = pathutil.resolve(taskFolder, './result');
42
+ let progressRootFolder = pathutil.resolve(taskFolder, './progress');
43
+ let resultsRootFolder = pathutil.resolve(taskFolder, './results');
44
+
45
+ let taskFolderNew = pathutil.resolve(progressRootFolder, './new');
46
+ let taskFolderRunning = pathutil.resolve(progressRootFolder, './running');
47
+ let taskFolderFinished = pathutil.resolve(progressRootFolder, './finished');
48
+ let taskFolderFailed= pathutil.resolve(progressRootFolder, './finished_with_errors');
49
+
50
+ let taskFolderResult = pathutil.resolve(resultsRootFolder, './succ');
51
+ let taskFolderResultFailed = pathutil.resolve(resultsRootFolder, './errors');
46
52
  //let mainRptFolder = pathutil.resolve(taskfolder, './report');
47
53
 
48
54
  //makeDir.sync(mainRptFolder);
49
55
  makeDir.sync(taskFolderNew);
50
56
  makeDir.sync(taskFolderRunning);
51
57
  makeDir.sync(taskFolderFinished);
58
+ makeDir.sync(taskFolderFailed);
52
59
  makeDir.sync(taskFolderResult);
60
+ makeDir.sync(taskFolderResultFailed);
53
61
 
54
62
  this.getAllActions().then((allactions)=>{
55
63
 
@@ -72,11 +80,15 @@ class SuperProducer {
72
80
  masterTaskId,
73
81
  allSubTasksId,
74
82
  //mainRptFolder,
83
+ progressRootFolder,
84
+ resultsRootFolder,
85
+
75
86
  taskFolder,
76
87
  taskFolderNew,
77
88
  taskFolderRunning,
78
89
  taskFolderFinished,
79
90
  taskFolderResult,
91
+ taskFolderResultFailed,
80
92
  });
81
93
  });
82
94
  }