UNPKG

flexbiz-server

Version:

Flexible Server

15 lines (14 loc) 6.9 kB
'use strict';const {Worker}=require("worker_threads"),fs=require("fs"),_=require("lodash"),crypto=require("crypto"),moment=require("moment"),redisCache=require("./redis-cache"); class WorkerPool{constructor($filename_i$$,$maxQueue_worker$$=0,$maxWorkers$$=1,$defaultTimeout$$=3E5,$pre_created_workers$$=0){if(!fs.existsSync($filename_i$$))throw Error("Worker file does not exist");this.filename=$filename_i$$;this.maxWorkers=$maxWorkers$$;(this.maxQueue=$maxQueue_worker$$)&&this.maxQueue<$maxWorkers$$&&(this.maxQueue=$maxWorkers$$);this.defaultTimeout=$defaultTimeout$$;this.pre_created_workers=$pre_created_workers$$;this.queue=[];this.queue_running=[];this.workers={};console.log("\u0110ang t\u1ea1o s\u1eb5n", $pre_created_workers$$,"workes/",$maxWorkers$$);for($filename_i$$=0;$filename_i$$<Math.min($pre_created_workers$$,$maxWorkers$$);$filename_i$$++)$maxQueue_worker$$=this.createWorker(),this.workers[$maxQueue_worker$$.id]=$maxQueue_worker$$}workerIsAlive($wk$$){return!$wk$$.worker||0>=$wk$$.worker.threadId||moment().diff(moment($wk$$.time_responded),"seconds")>(($wk$$.task||{}).timeout||1E4)/1E3?!1:!0}createWorker(){const $wk$$={id:`worker-${crypto.randomBytes(20).toString("hex")}`,isBusy:!1,time_responded:new Date}; $wk$$.worker=new Worker(this.filename);$wk$$.worker.on("message",async $message$$=>{$wk$$.time_responded=new Date;if("pong"!==$message$$)try{let $task$$;($task$$=$message$$.id_task?this.queue_running.find($q$$=>$q$$.id==$message$$.id_task):$wk$$.task)&&clearTimeout($task$$.timeoutId);if($task$$&&$task$$.callback)if($message$$.id_task&&$message$$.id_task!==$task$$.id)console.error("K\u1ebft qu\u1ea3 tr\u1ea3 v\u1ec1 kh\u00f4ng \u0111\u00fang cho task",$task$$.id,$message$$);else{$task$$.finished=new Date; $task$$.status=5;$task$$.message="\u0110\u00e3 th\u1ef1c hi\u1ec7n xong";$task$$.result=$message$$&&$message$$.map?void 0:$message$$;try{let {finished:$finished$$,status:$status$$,message:$message$$,result:$result$$}=$task$$;await redisCache.updateObject($task$$.id,{finished:$finished$$,status:$status$$,message:$message$$,result:$result$$})}catch($e$$){console.error("can't save task status",$e$$)}this.queue_running=this.queue_running.filter($q$$=>$q$$.id!==$task$$.id);$task$$.callback($message$$, $task$$.id)}delete $wk$$.task;$wk$$.isBusy=!1;this.processQueue()}catch($e$$){console.error($e$$)}});$wk$$.worker.on("error",$error$$=>{console.error("Worker error:",$error$$);$wk$$.worker.terminate()});$wk$$.worker.on("exit",async $code$$=>{console.error(`Worker exited with code ${$code$$}. Creating new worker...`);if($wk$$.task){let $task$$=this.queue_running.find($q$$=>$q$$.id==$wk$$.task.id_task);if($task$$){clearTimeout($task$$.timeoutId);$task$$.finished=new Date;$task$$.status=9;$task$$.message= "\u0110\u00e3 c\u00f3 l\u1ed7i x\u1ea3y ra trong h\u1ec7 th\u1ed1ng. H\u00e3y th\u1eed l\u1ea1i";let {finished:$finished$$,status:$status$$,message:$message$$,result:$result$$}=$task$$;try{await redisCache.updateObject($task$$.id,{finished:$finished$$,status:$status$$,message:$message$$,result:$result$$})}catch($e$$){console.error("can't save task status",$e$$)}$task$$.callback&&$task$$.callback({error:$message$$},$task$$.id);this.queue_running=this.queue_running.filter($q$$=>$q$$.id!==$task$$.id)}}delete this.workers[$wk$$.id]; $code$$=this.createWorker();this.workers[$code$$.id]=$code$$});return $wk$$}async processQueue($id_worker$$){for(let $i$$=0;$i$$<this.maxWorkers&&0!=this.queue.length;$i$$++){let $wk$$=Object.values(this.workers).find($w$$=>!$w$$.isBusy&&!$w$$.task&&(!$id_worker$$||$id_worker$$==$w$$.id));if(!$wk$$)if(Object.keys(this.workers).length<this.maxWorkers)console.log("T\u1ea1o th\u00eam worker m\u1edbi...",", s\u1ed1 l\u01b0\u1ee3ng workers hi\u1ec7n t\u1ea1i",Object.values(this.workers).length,", max:", this.maxWorkers),$wk$$=this.createWorker(),this.workers[$wk$$.id]=$wk$$;else break;if($wk$$){this.workerIsAlive($wk$$)||(console.error("Worker",$wk$$.id,"kh\u00f4ng c\u00f2n ho\u1ea1t \u0111\u1ed9ng. T\u1ea1o l\u1ea1i..."),delete this.workers[$wk$$.id],$wk$$=this.createWorker(),this.workers[$wk$$.id]=$wk$$);const $task$$=this.queue.shift();if($task$$){$task$$.status=2;$task$$.message="\u0110ang th\u1ef1c hi\u1ec7n";this.queue_running.push($task$$);try{let {finished:$finished$$,status:$status$$,message:$message$$, result:$result$$}=$task$$;await redisCache.updateObject($task$$.id,{finished:$finished$$,status:$status$$,message:$message$$,result:$result$$})}catch($e$$){console.error("can't save task status",$e$$)}$wk$$.isBusy=!0;$wk$$.task=$task$$;$task$$.params.id_worker=$wk$$.id;$wk$$.worker.postMessage($task$$.params);$task$$.timeoutId=setTimeout(async()=>{this.queue_running=this.queue_running.filter($q$$=>$q$$.id!==$task$$.id);$task$$.finished=new Date;$task$$.status=9;$task$$.message="\u0110\u00e3 h\u1ebft th\u1eddi gian th\u1ef1c hi\u1ec7n"; let {finished:$finished$$,status:$status$$,message:$message$$,result:$result$$}=$task$$;try{await redisCache.updateObject($task$$.id,{finished:$finished$$,status:$status$$,message:$message$$,result:$result$$})}catch($e$$){console.error("can't save task status",$e$$)}$task$$.callback&&$task$$.callback({error:$message$$},$task$$.id);delete $wk$$.task;$wk$$.isBusy=!1;this.processQueue()},$task$$.timeout||this.defaultTimeout)}}}}async pushToQueue($params$$,$callback$$,$timeout$$=0,$id_worker$$){$params$$.id_task|| ($params$$.id_task=`task-${crypto.randomBytes(20).toString("hex")}`);$timeout$$=$timeout$$||this.defaultTimeout;const $task$$={id:$params$$.id_task,start:new Date,params:_.cloneDeep($params$$),timeout:$timeout$$,status:0};delete $task$$.params.configs;delete $task$$.params.user;delete $task$$.params.configs;delete $task$$.params.data;$task$$.params.req&&(delete $task$$.params.req.user,delete $task$$.params.req.body,delete ($task$$.params.req.query||{}).access_token);try{await redisCache.setObject($params$$.id_task, $task$$),this.queue.push({id:$params$$.id_task,params:$params$$,callback:$callback$$,timeout:$timeout$$,status:0}),this.processQueue($id_worker$$)}catch($e$$){console.error("L\u1ed7i \u0111\u1ea9y task t\u1edbi queue",$e$$),$callback$$({error:$e$$.error||$e$$.message||$e$$})}}async exec($args_params$$,$callback$$=()=>{},$timeout$$=0){if(0<this.maxQueue&&this.queue.length>=this.maxQueue)$callback$$({error:"Queue is full"});else if($args_params$$.load)for(let $id_worker$$ of Object.keys(this.workers)){let $params$$= _.cloneDeep($args_params$$);this.pushToQueue($params$$,$callback$$,$timeout$$,$id_worker$$)}else $args_params$$=_.cloneDeep($args_params$$),this.pushToQueue($args_params$$,$callback$$,$timeout$$)}fullQueue(){return 0<this.maxQueue&&this.queue.length>=this.maxQueue}busy(){return 0==Object.values(this.workers).filter($w$$=>!$w$$.isBusy).length}destroy(){for(const $worker$$ of Object.values(this.workers))$worker$$.terminate();this.workers={};this.queue=[]}}module.exports=WorkerPool;