@eggjs/cluster
Version:
cluster manager for egg
128 lines (126 loc) • 3.06 kB
JavaScript
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 };