multi-tasks 1.2.8 → 2.0.0
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 +79 -40
- package/cmd.js +42 -0
- package/examples/example0/run-readme.js +88 -0
- package/examples/example0/run.js +32 -17
- package/index.js +1 -34
- package/monitors/cli.js +28 -0
- package/package.json +2 -1
- package/todo.txt +4 -0
- package/utils/asyncQueue.js +32 -0
- package/utils/backward-v1.js +11 -0
- package/utils/makedir.js +27 -1
- package/utils/randoms.js +15 -0
- package/utils/test/test_asyncqueue.js +116 -0
- package/workers/Multithread.js +175 -0
- package/workers/TaskMgr.js +186 -0
- package/workers/WorkerMgr.js +31 -0
- package/workers/asMaster.js +71 -0
- package/workers/asWorker.js +14 -0
- package/workers/helper.js +22 -0
- package/workers/index.js +8 -0
- package/workers/SuperConsumer.js +0 -106
- package/workers/SuperProducer.js +0 -97
- package/workers/master.js +0 -171
- package/workers/report/report_status.js +0 -52
- package/workers/taskSplitter.js +0 -30
- package/workers/test/MyConsumer.js +0 -25
- package/workers/test/MyProducer.js +0 -26
- package/workers/test/test_master.js +0 -12
- package/workers/test/test_producer.js +0 -4
- package/workers/test/test_splitter.js +0 -7
package/workers/SuperProducer.js
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
let fs = require('fs');
|
|
2
|
-
let pathutil = require('path');
|
|
3
|
-
let makeDir = require('../utils/makedir');
|
|
4
|
-
let splitter = require('./taskSplitter');
|
|
5
|
-
let fmtdigit = (n)=>{
|
|
6
|
-
return n > 9 ? "" + n: "0" + n;
|
|
7
|
-
}
|
|
8
|
-
let getDateTimeTxt = ()=>{
|
|
9
|
-
let d=new Date();
|
|
10
|
-
let YYYY=d.getFullYear()
|
|
11
|
-
let MM=fmtdigit(d.getMonth()+1);
|
|
12
|
-
let DD=fmtdigit(d.getDate());
|
|
13
|
-
let HH=fmtdigit(d.getHours());
|
|
14
|
-
let mm=fmtdigit(d.getMinutes());
|
|
15
|
-
let ss=fmtdigit(d.getSeconds());
|
|
16
|
-
return `${YYYY}-${MM}-${DD}_${HH}-${mm}-${ss}`;
|
|
17
|
-
};
|
|
18
|
-
class SuperProducer {
|
|
19
|
-
// constructor
|
|
20
|
-
constructor(taskname, parentfolder) {
|
|
21
|
-
this.taskname = taskname;
|
|
22
|
-
this.parentfolder = parentfolder;
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
getTaskName(){
|
|
27
|
-
return this.taskname;
|
|
28
|
-
}
|
|
29
|
-
getAllActions (){
|
|
30
|
-
//rewrite this method and return all your actions need to run
|
|
31
|
-
return new Promise();
|
|
32
|
-
}
|
|
33
|
-
generateTasks (quota, callback){
|
|
34
|
-
if(typeof quota === 'undefined' || !quota)quota=10;
|
|
35
|
-
let dateTimeText = getDateTimeTxt();//moment().format('YYYY-MM-DD_HH-mm-ss');
|
|
36
|
-
let masterTaskId = `${this.taskname}_${dateTimeText}`;
|
|
37
|
-
console.log('masterTaskId=',masterTaskId);
|
|
38
|
-
this.taskfolder = pathutil.resolve(this.parentfolder, masterTaskId)
|
|
39
|
-
let taskFolder = this.taskfolder;
|
|
40
|
-
//let taskfolder = pathutil.parse(__filename).dir;
|
|
41
|
-
//let taskFolder = pathutil.resolve(taskfolder, `./tasks/${masterTaskId}`);
|
|
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');
|
|
52
|
-
//let mainRptFolder = pathutil.resolve(taskfolder, './report');
|
|
53
|
-
|
|
54
|
-
//makeDir.sync(mainRptFolder);
|
|
55
|
-
makeDir.sync(taskFolderNew);
|
|
56
|
-
makeDir.sync(taskFolderRunning);
|
|
57
|
-
makeDir.sync(taskFolderFinished);
|
|
58
|
-
makeDir.sync(taskFolderFailed);
|
|
59
|
-
makeDir.sync(taskFolderResult);
|
|
60
|
-
makeDir.sync(taskFolderResultFailed);
|
|
61
|
-
|
|
62
|
-
this.getAllActions().then((allactions)=>{
|
|
63
|
-
|
|
64
|
-
let allSubTasks = splitter.split(allactions, quota);
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
console.log('allSubTasks=', allSubTasks.length)
|
|
68
|
-
|
|
69
|
-
let allSubTasksId = [];
|
|
70
|
-
|
|
71
|
-
allSubTasks.forEach((info, i)=>{
|
|
72
|
-
let subid = i;
|
|
73
|
-
info.subid = subid;
|
|
74
|
-
allSubTasksId.push(subid+'');
|
|
75
|
-
let taskfilepath = pathutil.resolve(taskFolderNew, `./${info.subid}.task.json`);
|
|
76
|
-
fs.writeFileSync(taskfilepath, JSON.stringify(info));
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
callback({
|
|
80
|
-
masterTaskId,
|
|
81
|
-
allSubTasksId,
|
|
82
|
-
//mainRptFolder,
|
|
83
|
-
progressRootFolder,
|
|
84
|
-
resultsRootFolder,
|
|
85
|
-
|
|
86
|
-
taskFolder,
|
|
87
|
-
taskFolderNew,
|
|
88
|
-
taskFolderRunning,
|
|
89
|
-
taskFolderFinished,
|
|
90
|
-
taskFolderResult,
|
|
91
|
-
taskFolderResultFailed,
|
|
92
|
-
});
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
module.exports = SuperProducer;
|
package/workers/master.js
DELETED
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
var fs = require('fs');
|
|
2
|
-
var pathutil = require('path');
|
|
3
|
-
const cluster = require('cluster');
|
|
4
|
-
const numCPUs = require('os').cpus().length;
|
|
5
|
-
const report_status = require('./report/report_status');
|
|
6
|
-
|
|
7
|
-
let MSG_REQUEST_TASKID = 'request_taskid';
|
|
8
|
-
/**
|
|
9
|
-
* masterId, the id of scanning flow
|
|
10
|
-
* -master, a master is a host of child_process computing
|
|
11
|
-
* -masterTaskId, id of a master, will rename to masterId
|
|
12
|
-
* -task, a child computing process
|
|
13
|
-
*/
|
|
14
|
-
let fmtdigit = (n)=>{
|
|
15
|
-
return n > 9 ? "" + n: "0" + n;
|
|
16
|
-
}
|
|
17
|
-
let getDateTimeTxt = ()=>{
|
|
18
|
-
let d=new Date();
|
|
19
|
-
let YYYY=d.getFullYear()
|
|
20
|
-
let MM=fmtdigit(d.getMonth()+1);
|
|
21
|
-
let DD=fmtdigit(d.getDate());
|
|
22
|
-
let HH=fmtdigit(d.getHours());
|
|
23
|
-
let mm=fmtdigit(d.getMinutes());
|
|
24
|
-
let ss=fmtdigit(d.getSeconds());
|
|
25
|
-
//return moment().format('YYYY-MM-DD HH:mm:ss');
|
|
26
|
-
return `${YYYY}-${MM}-${DD} ${HH}:${mm}:${ss}`;
|
|
27
|
-
};
|
|
28
|
-
let workidlist = new Set();
|
|
29
|
-
let addWorker = (wid)=>{
|
|
30
|
-
wid = wid+'';
|
|
31
|
-
workidlist.add(wid);
|
|
32
|
-
};
|
|
33
|
-
let removeWorker = (wid)=>{
|
|
34
|
-
wid = wid+'';
|
|
35
|
-
workidlist.delete(wid);
|
|
36
|
-
};
|
|
37
|
-
let hasWorker = ()=>{
|
|
38
|
-
return workidlist.size !== 0;
|
|
39
|
-
}
|
|
40
|
-
let run = (currentProducer, currentConsumer, opt)=>{
|
|
41
|
-
let defaultCPUs = numCPUs - 1;
|
|
42
|
-
if(typeof opt === 'undefined') opt = {};
|
|
43
|
-
let masterId = currentProducer.getTaskName();
|
|
44
|
-
if(typeof opt.quotaOfEachTask === 'undefined') opt.quotaOfEachTask = 1;
|
|
45
|
-
if(opt.numberOfWorks && !opt.numberOfWorkers) opt.numberOfWorkers = opt.numberOfWorks; //Backward compatible with the wrong variable name
|
|
46
|
-
if(typeof opt.numberOfWorkers === 'undefined') opt.numberOfWorkers = defaultCPUs;
|
|
47
|
-
console.log('master1, masterId=', masterId)
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
if(!masterId) throw `***Must assign masterId, pls use run.sh to run!***`
|
|
51
|
-
|
|
52
|
-
console.log('start', getDateTimeTxt())
|
|
53
|
-
|
|
54
|
-
if (cluster.isMaster) {//init
|
|
55
|
-
let numWorks = opt.numberOfWorkers;
|
|
56
|
-
console.log(`numCPUs ${numCPUs}`);
|
|
57
|
-
console.log(`numWorks ${numWorks}`);
|
|
58
|
-
console.log(`Master=${process.pid}`);
|
|
59
|
-
|
|
60
|
-
currentProducer.generateTasks(opt.quotaOfEachTask, (mainTaskInfo)=>{
|
|
61
|
-
//get ready
|
|
62
|
-
taskStack = mainTaskInfo.allSubTasksId;
|
|
63
|
-
let totalTaskNum = taskStack.length;
|
|
64
|
-
console.log( 'tasks=', mainTaskInfo.masterTaskId);
|
|
65
|
-
console.log( 'totalTaskNum=', totalTaskNum);
|
|
66
|
-
|
|
67
|
-
for (let i = 0; i < numWorks; i++) {
|
|
68
|
-
let worker = cluster.fork();
|
|
69
|
-
addWorker(worker.id)
|
|
70
|
-
worker.on('message', function(message) {
|
|
71
|
-
//console.log(`(master).${process.pid} got: '${JSON.stringify(message)}' from w.${worker.process.pid}`);
|
|
72
|
-
if(message === MSG_REQUEST_TASKID){
|
|
73
|
-
if(taskStack.length > 0){
|
|
74
|
-
let subTaskId = taskStack.shift();
|
|
75
|
-
let _sendMsg = ()=>{
|
|
76
|
-
worker.send({
|
|
77
|
-
startTimestamp: new Date()*1,
|
|
78
|
-
mainTaskInfo,
|
|
79
|
-
subTaskId,
|
|
80
|
-
totalTaskNum
|
|
81
|
-
},()=>{
|
|
82
|
-
//handler
|
|
83
|
-
}, {
|
|
84
|
-
keepOpen: (typeof opt.keepOpen === 'undefined') ? false : opt.keepOpen
|
|
85
|
-
})
|
|
86
|
-
};
|
|
87
|
-
_sendMsg();
|
|
88
|
-
}else{
|
|
89
|
-
removeWorker(worker.id)
|
|
90
|
-
worker.kill();
|
|
91
|
-
console.log('no task left.', getDateTimeTxt());
|
|
92
|
-
if(!hasWorker()){
|
|
93
|
-
console.log('all done!')
|
|
94
|
-
let taskFolder = mainTaskInfo.taskFolder;
|
|
95
|
-
let dataForNextMission = {
|
|
96
|
-
...mainTaskInfo
|
|
97
|
-
};
|
|
98
|
-
let dataPath = pathutil.resolve(taskFolder, `./extractTaskData-${masterId}.json`);
|
|
99
|
-
fs.writeFileSync(dataPath, JSON.stringify(dataForNextMission))
|
|
100
|
-
console.log('dataForNextMission=', dataPath);
|
|
101
|
-
if(opt.onFinish) {
|
|
102
|
-
opt.taskFolder = taskFolder;
|
|
103
|
-
let report = report_status.getReport(opt);
|
|
104
|
-
opt.onFinish(report);
|
|
105
|
-
}
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
} else {
|
|
115
|
-
let worker = cluster.worker;
|
|
116
|
-
//console.log(`>[w]=${process.pid} started`);
|
|
117
|
-
process.on('message', function(message) {});
|
|
118
|
-
worker.on('message', function(message) {
|
|
119
|
-
if(message.subTaskId){
|
|
120
|
-
let mainTaskInfo = message.mainTaskInfo;
|
|
121
|
-
//console.log(message);
|
|
122
|
-
let subTaskFilePath = pathutil.resolve(mainTaskInfo.taskFolderNew, `./${message.subTaskId}.task.json`);
|
|
123
|
-
let subTaskInfo = JSON.parse(fs.readFileSync(subTaskFilePath));
|
|
124
|
-
//let subTaskInfo = message.subTaskInfo;
|
|
125
|
-
let subid = subTaskInfo.subid;
|
|
126
|
-
if(mainTaskInfo){
|
|
127
|
-
console.log(`[Task Start]: "${subid}"`, `${subid}/${message.totalTaskNum}`, `pid=${process.pid}`, getDateTimeTxt());
|
|
128
|
-
//fs.writeFileSync(pathutil.resolve(mainTaskInfo.taskFolderFinished, `./${subid}`), subTaskInfo.tasksLen);
|
|
129
|
-
if(0){//mock
|
|
130
|
-
setTimeout(()=>{
|
|
131
|
-
worker.send(MSG_REQUEST_TASKID);//request new task
|
|
132
|
-
}, 100);
|
|
133
|
-
}else{//real
|
|
134
|
-
currentConsumer.runTasks(mainTaskInfo, subTaskInfo, message).then((report)=>{
|
|
135
|
-
let endTimestamp = new Date()*1;
|
|
136
|
-
let cost = report.startTimestamp - endTimestamp;
|
|
137
|
-
|
|
138
|
-
console.log(`[Task Finished] "${report.mainid}"."${report.subid}".`, getDateTimeTxt(), `cost=${cost}ms`)
|
|
139
|
-
worker.send(MSG_REQUEST_TASKID);//request new task
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
}else{
|
|
143
|
-
console.log('Can not find: message.subTaskInfo')
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
});
|
|
147
|
-
worker.send(MSG_REQUEST_TASKID);//request new task
|
|
148
|
-
|
|
149
|
-
}
|
|
150
|
-
};
|
|
151
|
-
let start = (ProducerClass, ConsumerClass, taskConfig)=>{
|
|
152
|
-
let taskId = Math.random()+'';
|
|
153
|
-
let {multi_task_parent_folder} = taskConfig;
|
|
154
|
-
|
|
155
|
-
let producer = new ProducerClass(`workers_of_${taskId}`, multi_task_parent_folder)
|
|
156
|
-
let consumer = new ConsumerClass();
|
|
157
|
-
|
|
158
|
-
console.log(producer.getTaskName())
|
|
159
|
-
//return;
|
|
160
|
-
|
|
161
|
-
//console.log(resp)
|
|
162
|
-
producer.setTaskTrunkInfo(taskConfig);
|
|
163
|
-
consumer.setTaskTrunkInfo(taskConfig);
|
|
164
|
-
run(producer, consumer, {
|
|
165
|
-
...taskConfig
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
module.exports = {
|
|
169
|
-
run,
|
|
170
|
-
start
|
|
171
|
-
};
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
var fs = require('fs');
|
|
2
|
-
var pathutil = require('path');
|
|
3
|
-
|
|
4
|
-
function countDirectChildFiles(directoryPath) {
|
|
5
|
-
const files = fs.readdirSync(directoryPath);
|
|
6
|
-
const directChildFiles = files.filter(file => {
|
|
7
|
-
const filePath = pathutil.join(directoryPath, file);
|
|
8
|
-
return fs.statSync(filePath).isFile();
|
|
9
|
-
});
|
|
10
|
-
return directChildFiles;
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
let getReport = (taskConfig)=>{
|
|
14
|
-
let {taskFolder} = taskConfig;
|
|
15
|
-
let folder_result_errors = pathutil.resolve(taskFolder, './results/errors');
|
|
16
|
-
let folder_result_succ = pathutil.resolve(taskFolder, './results/succ');
|
|
17
|
-
|
|
18
|
-
let folder_new = pathutil.resolve(taskFolder, './progress/new');
|
|
19
|
-
let folder_running = pathutil.resolve(taskFolder, './progress/running');
|
|
20
|
-
let folder_finished = pathutil.resolve(taskFolder, './progress/finished');
|
|
21
|
-
let folder_finished_with_errors = pathutil.resolve(taskFolder, './progress/finished_with_errors');
|
|
22
|
-
|
|
23
|
-
let files_new = countDirectChildFiles(folder_new);
|
|
24
|
-
let files_running = countDirectChildFiles(folder_running);
|
|
25
|
-
let files_finished = countDirectChildFiles(folder_finished);
|
|
26
|
-
let files_finished_with_errors = countDirectChildFiles(folder_finished_with_errors);
|
|
27
|
-
|
|
28
|
-
let report = {
|
|
29
|
-
taskConfig,
|
|
30
|
-
task_folders:{
|
|
31
|
-
folder_new,
|
|
32
|
-
folder_running,
|
|
33
|
-
folder_finished,
|
|
34
|
-
folder_finished_with_errors
|
|
35
|
-
},
|
|
36
|
-
result_folders:{
|
|
37
|
-
folder_result_errors,
|
|
38
|
-
folder_result_succ
|
|
39
|
-
},
|
|
40
|
-
tasks:{
|
|
41
|
-
new: files_new.length,
|
|
42
|
-
running: files_running.length,
|
|
43
|
-
finished: files_finished.length,
|
|
44
|
-
finished_with_errors: files_finished_with_errors.length,
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
return report;
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
module.exports = {
|
|
51
|
-
getReport
|
|
52
|
-
}
|
package/workers/taskSplitter.js
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
let split = (list, quota)=>{
|
|
2
|
-
let totalFilesLen = list.length
|
|
3
|
-
console.log('total:', totalFilesLen,'actions');
|
|
4
|
-
let allSubTasks = [];
|
|
5
|
-
let actions = [];
|
|
6
|
-
let currentIdx = 0;
|
|
7
|
-
let subid = 0;
|
|
8
|
-
list.forEach((act)=>{
|
|
9
|
-
currentIdx++;
|
|
10
|
-
actions.push(act)
|
|
11
|
-
if(actions.length>=quota){
|
|
12
|
-
allSubTasks.push({
|
|
13
|
-
actions,
|
|
14
|
-
tasksLen: actions.length
|
|
15
|
-
});
|
|
16
|
-
actions = [];
|
|
17
|
-
subid++;
|
|
18
|
-
}else if(totalFilesLen === currentIdx){
|
|
19
|
-
allSubTasks.push({
|
|
20
|
-
actions,
|
|
21
|
-
tasksLen: actions.length
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
//console.log(totalFilesLen,'-', currentIdx)
|
|
25
|
-
});
|
|
26
|
-
return allSubTasks;
|
|
27
|
-
}
|
|
28
|
-
module.exports = {
|
|
29
|
-
split
|
|
30
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
let SuperConsumer = require('../SuperConsumer');
|
|
2
|
-
class TestConsumer extends SuperConsumer {
|
|
3
|
-
|
|
4
|
-
// constructor
|
|
5
|
-
constructor(taskname, parentfolder) {
|
|
6
|
-
super(taskname, parentfolder)
|
|
7
|
-
|
|
8
|
-
}
|
|
9
|
-
run (mainTaskInfo, subTaskInfo, taskInfo, callback){
|
|
10
|
-
//do job
|
|
11
|
-
// console.log(`mainTaskInfo:`, mainTaskInfo)
|
|
12
|
-
// console.log(`subTaskInfo:`, subTaskInfo)
|
|
13
|
-
// console.log(`taskInfo:`, taskInfo)
|
|
14
|
-
//return;
|
|
15
|
-
//rewrite this
|
|
16
|
-
let succ = (Math.random()*1000)%3===0?true:false;
|
|
17
|
-
let result = {
|
|
18
|
-
succ
|
|
19
|
-
}
|
|
20
|
-
setTimeout(()=>{
|
|
21
|
-
callback(result);
|
|
22
|
-
}, Math.random()*1000)
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
module.exports = TestConsumer;
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
let SuperProducer = require('../SuperProducer');
|
|
2
|
-
class TestProducer extends SuperProducer {
|
|
3
|
-
|
|
4
|
-
// constructor
|
|
5
|
-
constructor(taskname, parentfolder) {
|
|
6
|
-
super(taskname, parentfolder)
|
|
7
|
-
|
|
8
|
-
}
|
|
9
|
-
getAllActions() {
|
|
10
|
-
return new Promise((resolve, reject)=>{
|
|
11
|
-
setTimeout(()=>{
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
let alltasks = []
|
|
15
|
-
for(let i=0;i<1673;i++){
|
|
16
|
-
alltasks.push({
|
|
17
|
-
xxx:111,
|
|
18
|
-
zzz:222
|
|
19
|
-
})
|
|
20
|
-
}
|
|
21
|
-
resolve(alltasks);
|
|
22
|
-
}, 3000)
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
module.exports = TestProducer;
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
let MyProducer = require('./MyProducer')
|
|
2
|
-
let MyConsumer = require('./MyConsumer')
|
|
3
|
-
let producer = new MyProducer(`atasknametest`, `D:\\tmp`)
|
|
4
|
-
let consumer = new MyConsumer()
|
|
5
|
-
let master = require('../master')
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
master.run(producer, consumer, {
|
|
9
|
-
|
|
10
|
-
quotaOfEachTask: 3
|
|
11
|
-
|
|
12
|
-
})
|