| 3 | const STRATEGIES = new Set([ 'roundrobin', 'random', 'leastbusy' ]); |
| 4 | |
| 5 | module.exports = class RpcWorkerPool { |
| 6 | constructor(path, size = 0, strategy = 'roundrobin') { |
| 7 | if (size === 0) this.size = CORES; // <1> |
| 8 | else if (size < 0) this.size = Math.max(CORES + size, 1); |
| 9 | else this.size = size; |
| 10 | |
| 11 | if (!STRATEGIES.has(strategy)) throw new TypeError('invalid strategy'); |
| 12 | this.strategy = strategy; // <2> |
| 13 | this.rr_index = -1; |
| 14 | |
| 15 | this.next_command_id = 0; |
| 16 | this.workers = []; // <3> |
| 17 | for (let i = 0; i < this.size; i++) { |
| 18 | const worker = new Worker(path); |
| 19 | this.workers.push({ worker, in_flight_commands: new Map() }); // <4> |
| 20 | worker.on('message', (msg) => { |
| 21 | this.onMessageHandler(msg, i); |
| 22 | }); |
| 23 | } |
| 24 | } |
| 25 | // THIS LINE SHOULD NOT APPEAR IN PRINT |
| 26 | onMessageHandler(msg, worker_id) { |
| 27 | const worker = this.workers[worker_id]; |
| 28 | const { result, error, id } = msg; |
| 29 | const { resolve, reject } = worker.in_flight_commands.get(id); |
| 30 | worker.in_flight_commands.delete(id); |
| 31 | if (error) reject(error); |
| 32 | else resolve(result); |
| 33 | } |
| 34 | // THIS LINE SHOULD NOT APPEAR IN PRINT |
| 35 | exec(method, ...args) { |
| 36 | const id = ++this.next_command_id; |
| 37 | let resolve, reject; |
| 38 | const promise = new Promise((res, rej) => { resolve = res; reject = rej; }); |
| 39 | const worker = this.getWorker(); // <1> |
| 40 | worker.in_flight_commands.set(id, { resolve, reject }); |
| 41 | worker.worker.postMessage({ method, params: args, id }); |
| 42 | return promise; |
| 43 | } |
| 44 | // THIS LINE SHOULD NOT APPEAR IN PRINT |
| 45 | getWorker() { |
| 46 | let id; |
| 47 | if (this.strategy === 'random') { |
| 48 | id = Math.floor(Math.random() * this.size); |
| 49 | } else if (this.strategy === 'roundrobin') { |
| 50 | this.rr_index++; |
| 51 | if (this.rr_index >= this.size) this.rr_index = 0; |
| 52 | id = this.rr_index; |
| 53 | } else if (this.strategy === 'leastbusy') { |
| 54 | let min = Infinity; |
| 55 | for (let i = 0; i < this.size; i++) { |
| 56 | let worker = this.workers[i]; |
| 57 | if (worker.in_flight_commands.size < min) { |
| 58 | min = worker.in_flight_commands.size; |
| 59 | id = i; |
| 60 | } |
| 61 | } |
| 62 | } |
nothing calls this directly
no outgoing calls
no test coverage detected