@eggjs/cluster
Version:
cluster manager for egg
144 lines (142 loc) • 3.63 kB
JavaScript
import { debuglog } from "node:util";
import workerThreads from "node:worker_threads";
//#region src/utils/messenger.ts
const debug = debuglog("egg/cluster/messenger");
/**
* master messenger, provide communication between parent, master, agent and app.
*
* ┌────────┐
* │ parent │
* /└────────┘\
* / | \
* / ┌────────┐ \
* / │ master │ \
* / └────────┘ \
* / / \ \
* ┌───────┐ ┌───────┐
* │ agent │ ------- │ app │
* └───────┘ └───────┘
*
*
* in app worker
*
* ```js
* process.send({
* action: 'xxx',
* data: '',
* to: 'agent/master/parent', // default to agent
* });
* ```
*
* in agent worker
*
* ```js
* process.send({
* action: 'xxx',
* data: '',
* to: 'app/master/parent', // default to app
* });
* ```
*
* in parent
*
* ```js
* process.send({
* action: 'xxx',
* data: '',
* to: 'app/agent/master', // default to master
* });
* ```
*/
var Messenger = class {
#master;
#workerManager;
#hasParent;
constructor(master, workerManager) {
this.#master = master;
this.#workerManager = workerManager;
this.#hasParent = !!workerThreads.parentPort || !!process.send;
process.on("message", (msg) => {
msg.from = "parent";
this.send(msg);
});
process.once("disconnect", () => {
this.#hasParent = false;
});
}
/**
* send message
* @param {Object} data message body
* - {String} from from who
* - {String} to to who
*/
send(data) {
if (!data.from) data.from = "master";
const receiverWorkerId = data.receiverWorkerId ?? data.receiverPid;
if (receiverWorkerId) if (receiverWorkerId === String(process.pid)) data.to = "master";
else if (receiverWorkerId === String(this.#workerManager.getAgent().workerId)) data.to = "agent";
else data.to = "app";
if (!data.to) {
if (data.from === "agent") data.to = "app";
if (data.from === "app") data.to = "agent";
if (data.from === "parent") data.to = "master";
}
if (data.to === "master") {
debug("%s -> master, data: %j", data.from, data);
this.sendToMaster(data);
return;
}
if (data.to === "parent") {
debug("%s -> parent, data: %j", data.from, data);
this.sendToParent(data);
return;
}
if (data.to === "app") {
debug("%s -> %s, data: %j", data.from, data.to, data);
this.sendToAppWorker(data);
return;
}
if (data.to === "agent") {
debug("%s -> %s, data: %j", data.from, data.to, data);
this.sendToAgentWorker(data);
return;
}
}
/**
* send message to master self
* @param {Object} data message body
*/
sendToMaster(data) {
this.#master.emit(data.action, data.data);
}
/**
* send message to parent process
* @param {Object} data message body
*/
sendToParent(data) {
if (!this.#hasParent) return;
process.send(data);
}
/**
* send message to app worker
* @param {Object} data message body
*/
sendToAppWorker(data) {
for (const worker of this.#workerManager.listWorkers()) {
if (worker.state === "disconnected") continue;
const receiverWorkerId = data.receiverWorkerId ?? data.receiverPid;
if (receiverWorkerId && receiverWorkerId !== String(worker.workerId)) continue;
worker.send(data);
}
}
/**
* send message to agent worker
* @param {Object} data message body
*/
sendToAgentWorker(data) {
const agent = this.#workerManager.getAgent();
if (agent) agent.send(data);
}
};
//#endregion
export { Messenger };