UNPKG

@eggjs/cluster

Version:

cluster manager for egg

128 lines (126 loc) 3.06 kB
import { BaseAppUtils, BaseAppWorker } from "../../base/app.js"; import { Worker, parentPort, threadId } from "node:worker_threads"; import { setTimeout } from "node:timers/promises"; //#region src/utils/mode/impl/worker_threads/app.ts var AppThreadWorker = class extends BaseAppWorker { #state = "none"; #id; constructor(instance, id) { super(instance); this.#id = id; } get id() { return this.#id; } get workerId() { return this.instance.threadId; } get state() { return this.#state; } set state(val) { this.#state = val; } get exitedAfterDisconnect() { return true; } get exitCode() { return 0; } send(message) { this.instance.postMessage(message); } clean() { this.instance.removeAllListeners(); } static get workerId() { return threadId; } static on(event, listener) { parentPort.on(event, listener); } static send(message) { message.senderWorkerId = String(threadId); parentPort.postMessage(message); } static kill() { process.exit(1); } static gracefulExit(options) { process.on("exit", async (code) => { if (typeof options.beforeExit === "function") await options.beforeExit(); process.exit(code); }); } }; var AppThreadUtils = class extends BaseAppUtils { #workers = []; #forkSingle(appPath, options, id) { const worker = new Worker(appPath, options); this.#workers.push(worker); const appWorker = new AppThreadWorker(worker, id); this.emit("worker_forked", appWorker); appWorker.disableRefork = true; worker.on("message", (msg) => { if (typeof msg === "string") msg = { action: msg, data: msg }; msg.from = "app"; this.messenger.send(msg); }); this.log("[master] app_worker#%s (tid:%s) start", appWorker.id, appWorker.workerId); let debugPort = process.debugPort; if (this.options.isDebug) { debugPort++; this.messenger.send({ to: "parent", from: "app", action: "debug", data: { debugPort, pid: appWorker.workerId, workerId: appWorker.workerId } }); } worker.on("exit", async (code) => { appWorker.state = "dead"; this.messenger.send({ action: "app-exit", data: { workerId: appWorker.workerId, code }, to: "master", from: "app" }); await setTimeout(1e3); this.#forkSingle(appPath, options, id); }); } fork() { this.startTime = Date.now(); this.startSuccessCount = 0; const ports = this.options.ports ?? []; if (!ports.length) ports.push(this.options.port); this.options.workers = ports.length; let i = 0; do { const options = Object.assign({}, this.options, { port: ports[i] }); const argv = [JSON.stringify(options)]; this.#forkSingle(this.getAppWorkerFile(), { argv }, ++i); } while (i < ports.length); return this; } async kill() { for (const worker of this.#workers) { const id = Reflect.get(worker, "id"); this.log(`[master] kill app worker#${id} (worker_threads) by worker.terminate()`); worker.removeAllListeners(); worker.terminate(); } } }; //#endregion export { AppThreadUtils };