11cb0ef41Sopenharmony_ci'use strict'; 21cb0ef41Sopenharmony_ci 31cb0ef41Sopenharmony_ciconst { 41cb0ef41Sopenharmony_ci ArrayPrototypePush, 51cb0ef41Sopenharmony_ci ArrayPrototypeSlice, 61cb0ef41Sopenharmony_ci ArrayPrototypeSome, 71cb0ef41Sopenharmony_ci ObjectKeys, 81cb0ef41Sopenharmony_ci ObjectValues, 91cb0ef41Sopenharmony_ci SafeMap, 101cb0ef41Sopenharmony_ci StringPrototypeStartsWith, 111cb0ef41Sopenharmony_ci} = primordials; 121cb0ef41Sopenharmony_ciconst { 131cb0ef41Sopenharmony_ci codes: { 141cb0ef41Sopenharmony_ci ERR_SOCKET_BAD_PORT, 151cb0ef41Sopenharmony_ci }, 161cb0ef41Sopenharmony_ci} = require('internal/errors'); 171cb0ef41Sopenharmony_ci 181cb0ef41Sopenharmony_ciconst assert = require('internal/assert'); 191cb0ef41Sopenharmony_ciconst { fork } = require('child_process'); 201cb0ef41Sopenharmony_ciconst path = require('path'); 211cb0ef41Sopenharmony_ciconst EventEmitter = require('events'); 221cb0ef41Sopenharmony_ciconst RoundRobinHandle = require('internal/cluster/round_robin_handle'); 231cb0ef41Sopenharmony_ciconst SharedHandle = require('internal/cluster/shared_handle'); 241cb0ef41Sopenharmony_ciconst Worker = require('internal/cluster/worker'); 251cb0ef41Sopenharmony_ciconst { getInspectPort, isUsingInspector } = require('internal/util/inspector'); 261cb0ef41Sopenharmony_ciconst { internal, sendHelper } = require('internal/cluster/utils'); 271cb0ef41Sopenharmony_ciconst cluster = new EventEmitter(); 281cb0ef41Sopenharmony_ciconst intercom = new EventEmitter(); 291cb0ef41Sopenharmony_ciconst SCHED_NONE = 1; 301cb0ef41Sopenharmony_ciconst SCHED_RR = 2; 311cb0ef41Sopenharmony_ci 321cb0ef41Sopenharmony_cimodule.exports = cluster; 331cb0ef41Sopenharmony_ci 341cb0ef41Sopenharmony_ciconst handles = new SafeMap(); 351cb0ef41Sopenharmony_cicluster.isWorker = false; 361cb0ef41Sopenharmony_cicluster.isMaster = true; // Deprecated alias. Must be same as isPrimary. 371cb0ef41Sopenharmony_cicluster.isPrimary = true; 381cb0ef41Sopenharmony_cicluster.Worker = Worker; 391cb0ef41Sopenharmony_cicluster.workers = {}; 401cb0ef41Sopenharmony_cicluster.settings = {}; 411cb0ef41Sopenharmony_cicluster.SCHED_NONE = SCHED_NONE; // Leave it to the operating system. 421cb0ef41Sopenharmony_cicluster.SCHED_RR = SCHED_RR; // Primary distributes connections. 431cb0ef41Sopenharmony_ci 441cb0ef41Sopenharmony_cilet ids = 0; 451cb0ef41Sopenharmony_cilet initialized = false; 461cb0ef41Sopenharmony_ci 471cb0ef41Sopenharmony_ci// XXX(bnoordhuis) Fold cluster.schedulingPolicy into cluster.settings? 481cb0ef41Sopenharmony_cilet schedulingPolicy = process.env.NODE_CLUSTER_SCHED_POLICY; 491cb0ef41Sopenharmony_ciif (schedulingPolicy === 'rr') 501cb0ef41Sopenharmony_ci schedulingPolicy = SCHED_RR; 511cb0ef41Sopenharmony_cielse if (schedulingPolicy === 'none') 521cb0ef41Sopenharmony_ci schedulingPolicy = SCHED_NONE; 531cb0ef41Sopenharmony_cielse if (process.platform === 'win32') { 541cb0ef41Sopenharmony_ci // Round-robin doesn't perform well on 551cb0ef41Sopenharmony_ci // Windows due to the way IOCP is wired up. 561cb0ef41Sopenharmony_ci schedulingPolicy = SCHED_NONE; 571cb0ef41Sopenharmony_ci} else 581cb0ef41Sopenharmony_ci schedulingPolicy = SCHED_RR; 591cb0ef41Sopenharmony_ci 601cb0ef41Sopenharmony_cicluster.schedulingPolicy = schedulingPolicy; 611cb0ef41Sopenharmony_ci 621cb0ef41Sopenharmony_cicluster.setupPrimary = function(options) { 631cb0ef41Sopenharmony_ci const settings = { 641cb0ef41Sopenharmony_ci args: ArrayPrototypeSlice(process.argv, 2), 651cb0ef41Sopenharmony_ci exec: process.argv[1], 661cb0ef41Sopenharmony_ci execArgv: process.execArgv, 671cb0ef41Sopenharmony_ci silent: false, 681cb0ef41Sopenharmony_ci ...cluster.settings, 691cb0ef41Sopenharmony_ci ...options, 701cb0ef41Sopenharmony_ci }; 711cb0ef41Sopenharmony_ci 721cb0ef41Sopenharmony_ci // Tell V8 to write profile data for each process to a separate file. 731cb0ef41Sopenharmony_ci // Without --logfile=v8-%p.log, everything ends up in a single, unusable 741cb0ef41Sopenharmony_ci // file. (Unusable because what V8 logs are memory addresses and each 751cb0ef41Sopenharmony_ci // process has its own memory mappings.) 761cb0ef41Sopenharmony_ci if (ArrayPrototypeSome(settings.execArgv, 771cb0ef41Sopenharmony_ci (s) => StringPrototypeStartsWith(s, '--prof')) && 781cb0ef41Sopenharmony_ci !ArrayPrototypeSome(settings.execArgv, 791cb0ef41Sopenharmony_ci (s) => StringPrototypeStartsWith(s, '--logfile='))) { 801cb0ef41Sopenharmony_ci settings.execArgv = [...settings.execArgv, '--logfile=v8-%p.log']; 811cb0ef41Sopenharmony_ci } 821cb0ef41Sopenharmony_ci 831cb0ef41Sopenharmony_ci cluster.settings = settings; 841cb0ef41Sopenharmony_ci 851cb0ef41Sopenharmony_ci if (initialized === true) 861cb0ef41Sopenharmony_ci return process.nextTick(setupSettingsNT, settings); 871cb0ef41Sopenharmony_ci 881cb0ef41Sopenharmony_ci initialized = true; 891cb0ef41Sopenharmony_ci schedulingPolicy = cluster.schedulingPolicy; // Freeze policy. 901cb0ef41Sopenharmony_ci assert(schedulingPolicy === SCHED_NONE || schedulingPolicy === SCHED_RR, 911cb0ef41Sopenharmony_ci `Bad cluster.schedulingPolicy: ${schedulingPolicy}`); 921cb0ef41Sopenharmony_ci 931cb0ef41Sopenharmony_ci process.nextTick(setupSettingsNT, settings); 941cb0ef41Sopenharmony_ci 951cb0ef41Sopenharmony_ci process.on('internalMessage', (message) => { 961cb0ef41Sopenharmony_ci if (message.cmd !== 'NODE_DEBUG_ENABLED') 971cb0ef41Sopenharmony_ci return; 981cb0ef41Sopenharmony_ci 991cb0ef41Sopenharmony_ci for (const worker of ObjectValues(cluster.workers)) { 1001cb0ef41Sopenharmony_ci if (worker.state === 'online' || worker.state === 'listening') { 1011cb0ef41Sopenharmony_ci process._debugProcess(worker.process.pid); 1021cb0ef41Sopenharmony_ci } else { 1031cb0ef41Sopenharmony_ci worker.once('online', function() { 1041cb0ef41Sopenharmony_ci process._debugProcess(this.process.pid); 1051cb0ef41Sopenharmony_ci }); 1061cb0ef41Sopenharmony_ci } 1071cb0ef41Sopenharmony_ci } 1081cb0ef41Sopenharmony_ci }); 1091cb0ef41Sopenharmony_ci}; 1101cb0ef41Sopenharmony_ci 1111cb0ef41Sopenharmony_ci// Deprecated alias must be same as setupPrimary 1121cb0ef41Sopenharmony_cicluster.setupMaster = cluster.setupPrimary; 1131cb0ef41Sopenharmony_ci 1141cb0ef41Sopenharmony_cifunction setupSettingsNT(settings) { 1151cb0ef41Sopenharmony_ci cluster.emit('setup', settings); 1161cb0ef41Sopenharmony_ci} 1171cb0ef41Sopenharmony_ci 1181cb0ef41Sopenharmony_cifunction createWorkerProcess(id, env) { 1191cb0ef41Sopenharmony_ci const workerEnv = { ...process.env, ...env, NODE_UNIQUE_ID: `${id}` }; 1201cb0ef41Sopenharmony_ci const execArgv = [...cluster.settings.execArgv]; 1211cb0ef41Sopenharmony_ci 1221cb0ef41Sopenharmony_ci if (cluster.settings.inspectPort === null) { 1231cb0ef41Sopenharmony_ci throw new ERR_SOCKET_BAD_PORT('Port', null, true); 1241cb0ef41Sopenharmony_ci } 1251cb0ef41Sopenharmony_ci if (isUsingInspector(cluster.settings.execArgv)) { 1261cb0ef41Sopenharmony_ci ArrayPrototypePush(execArgv, `--inspect-port=${getInspectPort(cluster.settings.inspectPort)}`); 1271cb0ef41Sopenharmony_ci } 1281cb0ef41Sopenharmony_ci 1291cb0ef41Sopenharmony_ci return fork(cluster.settings.exec, cluster.settings.args, { 1301cb0ef41Sopenharmony_ci cwd: cluster.settings.cwd, 1311cb0ef41Sopenharmony_ci env: workerEnv, 1321cb0ef41Sopenharmony_ci serialization: cluster.settings.serialization, 1331cb0ef41Sopenharmony_ci silent: cluster.settings.silent, 1341cb0ef41Sopenharmony_ci windowsHide: cluster.settings.windowsHide, 1351cb0ef41Sopenharmony_ci execArgv: execArgv, 1361cb0ef41Sopenharmony_ci stdio: cluster.settings.stdio, 1371cb0ef41Sopenharmony_ci gid: cluster.settings.gid, 1381cb0ef41Sopenharmony_ci uid: cluster.settings.uid, 1391cb0ef41Sopenharmony_ci }); 1401cb0ef41Sopenharmony_ci} 1411cb0ef41Sopenharmony_ci 1421cb0ef41Sopenharmony_cifunction removeWorker(worker) { 1431cb0ef41Sopenharmony_ci assert(worker); 1441cb0ef41Sopenharmony_ci delete cluster.workers[worker.id]; 1451cb0ef41Sopenharmony_ci 1461cb0ef41Sopenharmony_ci if (ObjectKeys(cluster.workers).length === 0) { 1471cb0ef41Sopenharmony_ci assert(handles.size === 0, 'Resource leak detected.'); 1481cb0ef41Sopenharmony_ci intercom.emit('disconnect'); 1491cb0ef41Sopenharmony_ci } 1501cb0ef41Sopenharmony_ci} 1511cb0ef41Sopenharmony_ci 1521cb0ef41Sopenharmony_cifunction removeHandlesForWorker(worker) { 1531cb0ef41Sopenharmony_ci assert(worker); 1541cb0ef41Sopenharmony_ci 1551cb0ef41Sopenharmony_ci handles.forEach((handle, key) => { 1561cb0ef41Sopenharmony_ci if (handle.remove(worker)) 1571cb0ef41Sopenharmony_ci handles.delete(key); 1581cb0ef41Sopenharmony_ci }); 1591cb0ef41Sopenharmony_ci} 1601cb0ef41Sopenharmony_ci 1611cb0ef41Sopenharmony_cicluster.fork = function(env) { 1621cb0ef41Sopenharmony_ci cluster.setupPrimary(); 1631cb0ef41Sopenharmony_ci const id = ++ids; 1641cb0ef41Sopenharmony_ci const workerProcess = createWorkerProcess(id, env); 1651cb0ef41Sopenharmony_ci const worker = new Worker({ 1661cb0ef41Sopenharmony_ci id: id, 1671cb0ef41Sopenharmony_ci process: workerProcess, 1681cb0ef41Sopenharmony_ci }); 1691cb0ef41Sopenharmony_ci 1701cb0ef41Sopenharmony_ci worker.on('message', function(message, handle) { 1711cb0ef41Sopenharmony_ci cluster.emit('message', this, message, handle); 1721cb0ef41Sopenharmony_ci }); 1731cb0ef41Sopenharmony_ci 1741cb0ef41Sopenharmony_ci worker.process.once('exit', (exitCode, signalCode) => { 1751cb0ef41Sopenharmony_ci /* 1761cb0ef41Sopenharmony_ci * Remove the worker from the workers list only 1771cb0ef41Sopenharmony_ci * if it has disconnected, otherwise we might 1781cb0ef41Sopenharmony_ci * still want to access it. 1791cb0ef41Sopenharmony_ci */ 1801cb0ef41Sopenharmony_ci if (!worker.isConnected()) { 1811cb0ef41Sopenharmony_ci removeHandlesForWorker(worker); 1821cb0ef41Sopenharmony_ci removeWorker(worker); 1831cb0ef41Sopenharmony_ci } 1841cb0ef41Sopenharmony_ci 1851cb0ef41Sopenharmony_ci worker.exitedAfterDisconnect = !!worker.exitedAfterDisconnect; 1861cb0ef41Sopenharmony_ci worker.state = 'dead'; 1871cb0ef41Sopenharmony_ci worker.emit('exit', exitCode, signalCode); 1881cb0ef41Sopenharmony_ci cluster.emit('exit', worker, exitCode, signalCode); 1891cb0ef41Sopenharmony_ci }); 1901cb0ef41Sopenharmony_ci 1911cb0ef41Sopenharmony_ci worker.process.once('disconnect', () => { 1921cb0ef41Sopenharmony_ci /* 1931cb0ef41Sopenharmony_ci * Now is a good time to remove the handles 1941cb0ef41Sopenharmony_ci * associated with this worker because it is 1951cb0ef41Sopenharmony_ci * not connected to the primary anymore. 1961cb0ef41Sopenharmony_ci */ 1971cb0ef41Sopenharmony_ci removeHandlesForWorker(worker); 1981cb0ef41Sopenharmony_ci 1991cb0ef41Sopenharmony_ci /* 2001cb0ef41Sopenharmony_ci * Remove the worker from the workers list only 2011cb0ef41Sopenharmony_ci * if its process has exited. Otherwise, we might 2021cb0ef41Sopenharmony_ci * still want to access it. 2031cb0ef41Sopenharmony_ci */ 2041cb0ef41Sopenharmony_ci if (worker.isDead()) 2051cb0ef41Sopenharmony_ci removeWorker(worker); 2061cb0ef41Sopenharmony_ci 2071cb0ef41Sopenharmony_ci worker.exitedAfterDisconnect = !!worker.exitedAfterDisconnect; 2081cb0ef41Sopenharmony_ci worker.state = 'disconnected'; 2091cb0ef41Sopenharmony_ci worker.emit('disconnect'); 2101cb0ef41Sopenharmony_ci cluster.emit('disconnect', worker); 2111cb0ef41Sopenharmony_ci }); 2121cb0ef41Sopenharmony_ci 2131cb0ef41Sopenharmony_ci worker.process.on('internalMessage', internal(worker, onmessage)); 2141cb0ef41Sopenharmony_ci process.nextTick(emitForkNT, worker); 2151cb0ef41Sopenharmony_ci cluster.workers[worker.id] = worker; 2161cb0ef41Sopenharmony_ci return worker; 2171cb0ef41Sopenharmony_ci}; 2181cb0ef41Sopenharmony_ci 2191cb0ef41Sopenharmony_cifunction emitForkNT(worker) { 2201cb0ef41Sopenharmony_ci cluster.emit('fork', worker); 2211cb0ef41Sopenharmony_ci} 2221cb0ef41Sopenharmony_ci 2231cb0ef41Sopenharmony_cicluster.disconnect = function(cb) { 2241cb0ef41Sopenharmony_ci const workers = ObjectKeys(cluster.workers); 2251cb0ef41Sopenharmony_ci 2261cb0ef41Sopenharmony_ci if (workers.length === 0) { 2271cb0ef41Sopenharmony_ci process.nextTick(() => intercom.emit('disconnect')); 2281cb0ef41Sopenharmony_ci } else { 2291cb0ef41Sopenharmony_ci for (const worker of ObjectValues(cluster.workers)) { 2301cb0ef41Sopenharmony_ci if (worker.isConnected()) { 2311cb0ef41Sopenharmony_ci worker.disconnect(); 2321cb0ef41Sopenharmony_ci } 2331cb0ef41Sopenharmony_ci } 2341cb0ef41Sopenharmony_ci } 2351cb0ef41Sopenharmony_ci 2361cb0ef41Sopenharmony_ci if (typeof cb === 'function') 2371cb0ef41Sopenharmony_ci intercom.once('disconnect', cb); 2381cb0ef41Sopenharmony_ci}; 2391cb0ef41Sopenharmony_ci 2401cb0ef41Sopenharmony_ciconst methodMessageMapping = { 2411cb0ef41Sopenharmony_ci close, 2421cb0ef41Sopenharmony_ci exitedAfterDisconnect, 2431cb0ef41Sopenharmony_ci listening, 2441cb0ef41Sopenharmony_ci online, 2451cb0ef41Sopenharmony_ci queryServer, 2461cb0ef41Sopenharmony_ci}; 2471cb0ef41Sopenharmony_ci 2481cb0ef41Sopenharmony_cifunction onmessage(message, handle) { 2491cb0ef41Sopenharmony_ci const worker = this; 2501cb0ef41Sopenharmony_ci 2511cb0ef41Sopenharmony_ci const fn = methodMessageMapping[message.act]; 2521cb0ef41Sopenharmony_ci 2531cb0ef41Sopenharmony_ci if (typeof fn === 'function') 2541cb0ef41Sopenharmony_ci fn(worker, message); 2551cb0ef41Sopenharmony_ci} 2561cb0ef41Sopenharmony_ci 2571cb0ef41Sopenharmony_cifunction online(worker) { 2581cb0ef41Sopenharmony_ci worker.state = 'online'; 2591cb0ef41Sopenharmony_ci worker.emit('online'); 2601cb0ef41Sopenharmony_ci cluster.emit('online', worker); 2611cb0ef41Sopenharmony_ci} 2621cb0ef41Sopenharmony_ci 2631cb0ef41Sopenharmony_cifunction exitedAfterDisconnect(worker, message) { 2641cb0ef41Sopenharmony_ci worker.exitedAfterDisconnect = true; 2651cb0ef41Sopenharmony_ci send(worker, { ack: message.seq }); 2661cb0ef41Sopenharmony_ci} 2671cb0ef41Sopenharmony_ci 2681cb0ef41Sopenharmony_cifunction queryServer(worker, message) { 2691cb0ef41Sopenharmony_ci // Stop processing if worker already disconnecting 2701cb0ef41Sopenharmony_ci if (worker.exitedAfterDisconnect) 2711cb0ef41Sopenharmony_ci return; 2721cb0ef41Sopenharmony_ci 2731cb0ef41Sopenharmony_ci const key = `${message.address}:${message.port}:${message.addressType}:` + 2741cb0ef41Sopenharmony_ci `${message.fd}:${message.index}`; 2751cb0ef41Sopenharmony_ci let handle = handles.get(key); 2761cb0ef41Sopenharmony_ci 2771cb0ef41Sopenharmony_ci if (handle === undefined) { 2781cb0ef41Sopenharmony_ci let address = message.address; 2791cb0ef41Sopenharmony_ci 2801cb0ef41Sopenharmony_ci // Find shortest path for unix sockets because of the ~100 byte limit 2811cb0ef41Sopenharmony_ci if (message.port < 0 && typeof address === 'string' && 2821cb0ef41Sopenharmony_ci process.platform !== 'win32') { 2831cb0ef41Sopenharmony_ci 2841cb0ef41Sopenharmony_ci address = path.relative(process.cwd(), address); 2851cb0ef41Sopenharmony_ci 2861cb0ef41Sopenharmony_ci if (message.address.length < address.length) 2871cb0ef41Sopenharmony_ci address = message.address; 2881cb0ef41Sopenharmony_ci } 2891cb0ef41Sopenharmony_ci 2901cb0ef41Sopenharmony_ci // UDP is exempt from round-robin connection balancing for what should 2911cb0ef41Sopenharmony_ci // be obvious reasons: it's connectionless. There is nothing to send to 2921cb0ef41Sopenharmony_ci // the workers except raw datagrams and that's pointless. 2931cb0ef41Sopenharmony_ci if (schedulingPolicy !== SCHED_RR || 2941cb0ef41Sopenharmony_ci message.addressType === 'udp4' || 2951cb0ef41Sopenharmony_ci message.addressType === 'udp6') { 2961cb0ef41Sopenharmony_ci handle = new SharedHandle(key, address, message); 2971cb0ef41Sopenharmony_ci } else { 2981cb0ef41Sopenharmony_ci handle = new RoundRobinHandle(key, address, message); 2991cb0ef41Sopenharmony_ci } 3001cb0ef41Sopenharmony_ci 3011cb0ef41Sopenharmony_ci handles.set(key, handle); 3021cb0ef41Sopenharmony_ci } 3031cb0ef41Sopenharmony_ci 3041cb0ef41Sopenharmony_ci if (!handle.data) 3051cb0ef41Sopenharmony_ci handle.data = message.data; 3061cb0ef41Sopenharmony_ci 3071cb0ef41Sopenharmony_ci // Set custom server data 3081cb0ef41Sopenharmony_ci handle.add(worker, (errno, reply, handle) => { 3091cb0ef41Sopenharmony_ci const { data } = handles.get(key); 3101cb0ef41Sopenharmony_ci 3111cb0ef41Sopenharmony_ci if (errno) 3121cb0ef41Sopenharmony_ci handles.delete(key); // Gives other workers a chance to retry. 3131cb0ef41Sopenharmony_ci 3141cb0ef41Sopenharmony_ci send(worker, { 3151cb0ef41Sopenharmony_ci errno, 3161cb0ef41Sopenharmony_ci key, 3171cb0ef41Sopenharmony_ci ack: message.seq, 3181cb0ef41Sopenharmony_ci data, 3191cb0ef41Sopenharmony_ci ...reply, 3201cb0ef41Sopenharmony_ci }, handle); 3211cb0ef41Sopenharmony_ci }); 3221cb0ef41Sopenharmony_ci} 3231cb0ef41Sopenharmony_ci 3241cb0ef41Sopenharmony_cifunction listening(worker, message) { 3251cb0ef41Sopenharmony_ci const info = { 3261cb0ef41Sopenharmony_ci addressType: message.addressType, 3271cb0ef41Sopenharmony_ci address: message.address, 3281cb0ef41Sopenharmony_ci port: message.port, 3291cb0ef41Sopenharmony_ci fd: message.fd, 3301cb0ef41Sopenharmony_ci }; 3311cb0ef41Sopenharmony_ci 3321cb0ef41Sopenharmony_ci worker.state = 'listening'; 3331cb0ef41Sopenharmony_ci worker.emit('listening', info); 3341cb0ef41Sopenharmony_ci cluster.emit('listening', worker, info); 3351cb0ef41Sopenharmony_ci} 3361cb0ef41Sopenharmony_ci 3371cb0ef41Sopenharmony_ci// Server in worker is closing, remove from list. The handle may have been 3381cb0ef41Sopenharmony_ci// removed by a prior call to removeHandlesForWorker() so guard against that. 3391cb0ef41Sopenharmony_cifunction close(worker, message) { 3401cb0ef41Sopenharmony_ci const key = message.key; 3411cb0ef41Sopenharmony_ci const handle = handles.get(key); 3421cb0ef41Sopenharmony_ci 3431cb0ef41Sopenharmony_ci if (handle && handle.remove(worker)) 3441cb0ef41Sopenharmony_ci handles.delete(key); 3451cb0ef41Sopenharmony_ci} 3461cb0ef41Sopenharmony_ci 3471cb0ef41Sopenharmony_cifunction send(worker, message, handle, cb) { 3481cb0ef41Sopenharmony_ci return sendHelper(worker.process, message, handle, cb); 3491cb0ef41Sopenharmony_ci} 3501cb0ef41Sopenharmony_ci 3511cb0ef41Sopenharmony_ci// Extend generic Worker with methods specific to the primary process. 3521cb0ef41Sopenharmony_ciWorker.prototype.disconnect = function() { 3531cb0ef41Sopenharmony_ci this.exitedAfterDisconnect = true; 3541cb0ef41Sopenharmony_ci send(this, { act: 'disconnect' }); 3551cb0ef41Sopenharmony_ci removeHandlesForWorker(this); 3561cb0ef41Sopenharmony_ci removeWorker(this); 3571cb0ef41Sopenharmony_ci return this; 3581cb0ef41Sopenharmony_ci}; 3591cb0ef41Sopenharmony_ci 3601cb0ef41Sopenharmony_ciWorker.prototype.destroy = function(signo) { 3611cb0ef41Sopenharmony_ci const proc = this.process; 3621cb0ef41Sopenharmony_ci const signal = signo || 'SIGTERM'; 3631cb0ef41Sopenharmony_ci 3641cb0ef41Sopenharmony_ci proc.kill(signal); 3651cb0ef41Sopenharmony_ci}; 366