@eggjs/cluster 4.0.2-beta.25 → 4.0.2-beta.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent_worker.js +5 -24
- package/dist/app_worker.js +5 -130
- package/dist/utils/mode/impl/process/agent.d.ts +0 -4
- package/dist/utils/mode/impl/process/agent.js +7 -14
- package/dist/utils/mode/impl/process/app.d.ts +0 -6
- package/dist/utils/mode/impl/process/app.js +8 -27
- package/dist/utils/mode/impl/worker_threads/agent.d.ts +0 -4
- package/dist/utils/mode/impl/worker_threads/agent.js +2 -17
- package/dist/utils/mode/impl/worker_threads/app.d.ts +0 -6
- package/dist/utils/mode/impl/worker_threads/app.js +5 -23
- package/dist/utils/options.d.ts +16 -0
- package/dist/utils/options.js +19 -0
- package/dist/worker_protocol/agent.d.ts +23 -0
- package/dist/worker_protocol/agent.js +32 -0
- package/dist/worker_protocol/app.d.ts +30 -0
- package/dist/worker_protocol/app.js +141 -0
- package/dist/worker_protocol/process.d.ts +14 -0
- package/dist/worker_protocol/process.js +38 -0
- package/dist/worker_protocol/worker-thread.d.ts +11 -0
- package/dist/worker_protocol/worker-thread.js +34 -0
- package/dist/worker_protocol.d.ts +5 -0
- package/dist/worker_protocol.js +6 -0
- package/package.json +8 -6
package/dist/agent_worker.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { startAgentWorker } from "./worker_protocol/agent.js";
|
|
2
|
+
import { createProcessWorkerIO } from "./worker_protocol/process.js";
|
|
3
|
+
import { createWorkerThreadIO } from "./worker_protocol/worker-thread.js";
|
|
3
4
|
import { debuglog } from "node:util";
|
|
4
5
|
import { EggConsoleLogger } from "egg-logger";
|
|
5
6
|
import { importModule } from "@eggjs/utils";
|
|
@@ -16,9 +17,7 @@ const debug = debuglog("egg/cluster/agent_worker");
|
|
|
16
17
|
async function main() {
|
|
17
18
|
const options = JSON.parse(process.argv[2]);
|
|
18
19
|
if (options.require) for (const mod of options.require) await importModule(mod, { paths: [options.baseDir] });
|
|
19
|
-
|
|
20
|
-
if (options.startMode === "worker_threads") AgentWorker = AgentThreadWorker;
|
|
21
|
-
else AgentWorker = AgentProcessWorker;
|
|
20
|
+
const workerIO = options.startMode === "worker_threads" ? createWorkerThreadIO() : createProcessWorkerIO();
|
|
22
21
|
const consoleLogger = new EggConsoleLogger({ level: process.env.EGG_AGENT_WORKER_LOGGER_LEVEL });
|
|
23
22
|
const { Agent } = await importModule(options.framework, { paths: [options.baseDir] });
|
|
24
23
|
debug("new Agent with options %j", options);
|
|
@@ -29,25 +28,7 @@ async function main() {
|
|
|
29
28
|
consoleLogger.error(err);
|
|
30
29
|
throw err;
|
|
31
30
|
}
|
|
32
|
-
|
|
33
|
-
consoleLogger.error(err);
|
|
34
|
-
consoleLogger.error("[agent_worker] start error, exiting with code:1");
|
|
35
|
-
AgentWorker.kill();
|
|
36
|
-
}
|
|
37
|
-
agent.ready((err) => {
|
|
38
|
-
if (err) return;
|
|
39
|
-
agent.removeListener("error", startErrorHandler);
|
|
40
|
-
AgentWorker.send({
|
|
41
|
-
action: "agent-start",
|
|
42
|
-
to: "master"
|
|
43
|
-
});
|
|
44
|
-
});
|
|
45
|
-
agent.once("error", startErrorHandler);
|
|
46
|
-
AgentWorker.gracefulExit({
|
|
47
|
-
logger: consoleLogger,
|
|
48
|
-
label: "agent_worker",
|
|
49
|
-
beforeExit: () => agent.close()
|
|
50
|
-
});
|
|
31
|
+
startAgentWorker(agent, workerIO, consoleLogger);
|
|
51
32
|
}
|
|
52
33
|
main();
|
|
53
34
|
|
package/dist/app_worker.js
CHANGED
|
@@ -1,27 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import os from "node:os";
|
|
1
|
+
import { createProcessWorkerIO } from "./worker_protocol/process.js";
|
|
2
|
+
import { createWorkerThreadIO } from "./worker_protocol/worker-thread.js";
|
|
3
|
+
import { startAppWorker } from "./worker_protocol/app.js";
|
|
5
4
|
import { debuglog } from "node:util";
|
|
6
5
|
import { EggConsoleLogger } from "egg-logger";
|
|
7
6
|
import { importModule } from "@eggjs/utils";
|
|
8
|
-
import { createServer } from "node:http";
|
|
9
|
-
import { createServer as createServer$1 } from "node:https";
|
|
10
7
|
|
|
11
8
|
//#region src/app_worker.ts
|
|
12
9
|
const debug = debuglog("egg/cluster/app_worker");
|
|
13
|
-
const REUSE_PORT_SUPPORTED_PLATFORMS = [
|
|
14
|
-
"linux",
|
|
15
|
-
"freebsd",
|
|
16
|
-
"sunos",
|
|
17
|
-
"aix"
|
|
18
|
-
];
|
|
19
10
|
async function main() {
|
|
20
11
|
const options = JSON.parse(process.argv[2]);
|
|
21
12
|
if (options.require) for (const mod of options.require) await importModule(mod, { paths: [options.baseDir] });
|
|
22
|
-
|
|
23
|
-
if (options.startMode === "worker_threads") AppWorker = AppThreadWorker;
|
|
24
|
-
else AppWorker = AppProcessWorker;
|
|
13
|
+
const workerIO = options.startMode === "worker_threads" ? createWorkerThreadIO() : createProcessWorkerIO();
|
|
25
14
|
const consoleLogger = new EggConsoleLogger({ level: process.env.EGG_APP_WORKER_LOGGER_LEVEL });
|
|
26
15
|
const { Application } = await importModule(options.framework, { paths: [options.baseDir] });
|
|
27
16
|
debug("[app_worker:%s] new Application with options %j", process.pid, options);
|
|
@@ -32,121 +21,7 @@ async function main() {
|
|
|
32
21
|
consoleLogger.error(err);
|
|
33
22
|
throw err;
|
|
34
23
|
}
|
|
35
|
-
app
|
|
36
|
-
function exitProcess() {
|
|
37
|
-
AppWorker.kill();
|
|
38
|
-
}
|
|
39
|
-
app.once("startTimeout", startTimeoutHandler);
|
|
40
|
-
function startTimeoutHandler() {
|
|
41
|
-
consoleLogger.error("[app_worker] start timeout, exiting with code:1");
|
|
42
|
-
exitProcess();
|
|
43
|
-
}
|
|
44
|
-
function startServer(err) {
|
|
45
|
-
if (err) {
|
|
46
|
-
consoleLogger.error(err);
|
|
47
|
-
consoleLogger.error("[app_worker] start error, exiting with code:1");
|
|
48
|
-
exitProcess();
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
const clusterConfig = app.config.cluster ?? {};
|
|
52
|
-
const listenConfig = clusterConfig.listen ?? {};
|
|
53
|
-
const httpsOptions = {
|
|
54
|
-
...clusterConfig.https,
|
|
55
|
-
...options.https
|
|
56
|
-
};
|
|
57
|
-
const port = app.options.port = options.port || listenConfig.port;
|
|
58
|
-
const debugPort = options.debugPort;
|
|
59
|
-
const protocol = httpsOptions.key && httpsOptions.cert ? "https" : "http";
|
|
60
|
-
let reusePort = options.reusePort ?? listenConfig.reusePort ?? false;
|
|
61
|
-
if (reusePort && !REUSE_PORT_SUPPORTED_PLATFORMS.includes(os.platform())) {
|
|
62
|
-
reusePort = false;
|
|
63
|
-
debug("[app_worker:%s] platform %s is not supported for reusePort, set reusePort to false", process.pid, os.platform());
|
|
64
|
-
}
|
|
65
|
-
debug("[app_worker:%s] listenConfig: %j, real port: %o, protocol: %o, debugPort: %o, reusePort: %o", process.pid, listenConfig, port, protocol, debugPort, reusePort);
|
|
66
|
-
AppWorker.send({
|
|
67
|
-
to: "master",
|
|
68
|
-
action: "realport",
|
|
69
|
-
data: {
|
|
70
|
-
port,
|
|
71
|
-
protocol
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
app.removeListener("startTimeout", startTimeoutHandler);
|
|
75
|
-
let server;
|
|
76
|
-
let debugPortServer;
|
|
77
|
-
if (protocol === "https") {
|
|
78
|
-
httpsOptions.key = fs.readFileSync(httpsOptions.key);
|
|
79
|
-
httpsOptions.cert = fs.readFileSync(httpsOptions.cert);
|
|
80
|
-
httpsOptions.ca = httpsOptions.ca && fs.readFileSync(httpsOptions.ca);
|
|
81
|
-
server = createServer$1(httpsOptions, app.callback());
|
|
82
|
-
if (debugPort) debugPortServer = createServer(app.callback());
|
|
83
|
-
} else {
|
|
84
|
-
server = createServer(app.callback());
|
|
85
|
-
if (debugPort) debugPortServer = server;
|
|
86
|
-
}
|
|
87
|
-
server.once("error", (err$1) => {
|
|
88
|
-
consoleLogger.error("[app_worker] server got error: %s, code: %s", err$1.message, err$1.code);
|
|
89
|
-
exitProcess();
|
|
90
|
-
});
|
|
91
|
-
app.emit("server", server);
|
|
92
|
-
if (options.sticky && options.stickyWorkerPort) {
|
|
93
|
-
server.listen(options.stickyWorkerPort, "127.0.0.1");
|
|
94
|
-
AppWorker.on("message", (message, connection) => {
|
|
95
|
-
if (message !== "sticky-session:connection") return;
|
|
96
|
-
server.emit("connection", connection);
|
|
97
|
-
connection.resume();
|
|
98
|
-
});
|
|
99
|
-
} else {
|
|
100
|
-
if (listenConfig.path) server.listen(listenConfig.path);
|
|
101
|
-
else {
|
|
102
|
-
if (typeof port !== "number") {
|
|
103
|
-
consoleLogger.error("[app_worker:%s] port should be number, but got %s(%s)", process.pid, port, typeof port);
|
|
104
|
-
exitProcess();
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
if (reusePort) {
|
|
108
|
-
const listenOptions = {
|
|
109
|
-
port,
|
|
110
|
-
reusePort
|
|
111
|
-
};
|
|
112
|
-
if (listenConfig.hostname) listenOptions.host = listenConfig.hostname;
|
|
113
|
-
debug("[app_worker:%s] listen with reusePort options %j", process.pid, listenOptions);
|
|
114
|
-
server.listen(listenOptions);
|
|
115
|
-
} else {
|
|
116
|
-
const args = [port];
|
|
117
|
-
if (listenConfig.hostname) args.push(listenConfig.hostname);
|
|
118
|
-
debug("listen options %j", args);
|
|
119
|
-
server.listen(...args);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
if (debugPortServer) {
|
|
123
|
-
debug("listen on debug port: %s", debugPort);
|
|
124
|
-
debugPortServer.listen(debugPort);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
server.once("listening", () => {
|
|
128
|
-
let address = server.address() || { port };
|
|
129
|
-
if (typeof address === "string") address = {
|
|
130
|
-
address,
|
|
131
|
-
addressType: -1
|
|
132
|
-
};
|
|
133
|
-
debug("[app_worker:%s] listening at %j, reusePort: %o", process.pid, address, reusePort);
|
|
134
|
-
AppWorker.send({
|
|
135
|
-
to: "master",
|
|
136
|
-
action: "app-start",
|
|
137
|
-
data: {
|
|
138
|
-
address,
|
|
139
|
-
workerId: AppWorker.workerId
|
|
140
|
-
},
|
|
141
|
-
reusePort
|
|
142
|
-
});
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
AppWorker.gracefulExit({
|
|
146
|
-
logger: consoleLogger,
|
|
147
|
-
label: "app_worker",
|
|
148
|
-
beforeExit: () => app.close()
|
|
149
|
-
});
|
|
24
|
+
startAppWorker(app, options, workerIO, consoleLogger);
|
|
150
25
|
}
|
|
151
26
|
main();
|
|
152
27
|
|
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
import { BaseAgentUtils, BaseAgentWorker } from "../../base/agent.js";
|
|
2
2
|
import { MessageBody } from "../../../messenger.js";
|
|
3
3
|
import { ChildProcess } from "node:child_process";
|
|
4
|
-
import { Options } from "graceful-process";
|
|
5
4
|
|
|
6
5
|
//#region src/utils/mode/impl/process/agent.d.ts
|
|
7
6
|
declare class AgentProcessWorker extends BaseAgentWorker<ChildProcess> {
|
|
8
7
|
get workerId(): number;
|
|
9
8
|
send(message: MessageBody): void;
|
|
10
|
-
static send(message: MessageBody): void;
|
|
11
|
-
static kill(): void;
|
|
12
|
-
static gracefulExit(options: Options): void;
|
|
13
9
|
}
|
|
14
10
|
declare class AgentProcessUtils extends BaseAgentUtils {
|
|
15
11
|
#private;
|
|
@@ -3,7 +3,6 @@ import { terminate } from "../../../terminate.js";
|
|
|
3
3
|
import { BaseAgentUtils, BaseAgentWorker } from "../../base/agent.js";
|
|
4
4
|
import { debuglog } from "node:util";
|
|
5
5
|
import { fork } from "node:child_process";
|
|
6
|
-
import { graceful } from "graceful-process";
|
|
7
6
|
import { sendmessage } from "sendmessage";
|
|
8
7
|
|
|
9
8
|
//#region src/utils/mode/impl/process/agent.ts
|
|
@@ -15,17 +14,6 @@ var AgentProcessWorker = class extends BaseAgentWorker {
|
|
|
15
14
|
send(message) {
|
|
16
15
|
sendmessage(this.instance, message);
|
|
17
16
|
}
|
|
18
|
-
static send(message) {
|
|
19
|
-
message.senderWorkerId = String(process.pid);
|
|
20
|
-
process.send(message);
|
|
21
|
-
}
|
|
22
|
-
static kill() {
|
|
23
|
-
process.exitCode = 1;
|
|
24
|
-
process.kill(process.pid);
|
|
25
|
-
}
|
|
26
|
-
static gracefulExit(options) {
|
|
27
|
-
graceful(options);
|
|
28
|
-
}
|
|
29
17
|
};
|
|
30
18
|
var AgentProcessUtils = class extends BaseAgentUtils {
|
|
31
19
|
#agentProcess;
|
|
@@ -38,8 +26,13 @@ var AgentProcessUtils = class extends BaseAgentUtils {
|
|
|
38
26
|
if (process.platform === "win32") forkOptions.windowsHide = true;
|
|
39
27
|
const debugPort = process.env.EGG_AGENT_DEBUG_PORT ?? 5800;
|
|
40
28
|
if (this.options.isDebug) forkOptions.execArgv = process.execArgv.concat([`--inspect-port=${debugPort}`]);
|
|
29
|
+
if (this.options.agentSnapshotBlob) forkOptions.execArgv = [
|
|
30
|
+
...forkOptions.execArgv ?? process.execArgv,
|
|
31
|
+
"--snapshot-blob",
|
|
32
|
+
this.options.agentSnapshotBlob
|
|
33
|
+
];
|
|
41
34
|
debug("forkOptions: %j, args: %s", forkOptions, args);
|
|
42
|
-
const agentProcess = this.#agentProcess = fork(this.getAgentWorkerFile(), args, forkOptions);
|
|
35
|
+
const agentProcess = this.#agentProcess = fork(this.options.agentWorkerFile || this.getAgentWorkerFile(), args, forkOptions);
|
|
43
36
|
const agentWorker = this.instance = new AgentProcessWorker(agentProcess);
|
|
44
37
|
agentWorker.status = "starting";
|
|
45
38
|
agentWorker.id = ++this.#id;
|
|
@@ -93,4 +86,4 @@ var AgentProcessUtils = class extends BaseAgentUtils {
|
|
|
93
86
|
};
|
|
94
87
|
|
|
95
88
|
//#endregion
|
|
96
|
-
export { AgentProcessUtils
|
|
89
|
+
export { AgentProcessUtils };
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { BaseAppUtils, BaseAppWorker } from "../../base/app.js";
|
|
2
2
|
import { MessageBody } from "../../../messenger.js";
|
|
3
|
-
import { Options } from "graceful-process";
|
|
4
3
|
import { Worker } from "node:cluster";
|
|
5
4
|
|
|
6
5
|
//#region src/utils/mode/impl/process/app.d.ts
|
|
@@ -11,11 +10,6 @@ declare class AppProcessWorker extends BaseAppWorker<Worker> {
|
|
|
11
10
|
get exitCode(): number;
|
|
12
11
|
send(message: MessageBody): void;
|
|
13
12
|
clean(): void;
|
|
14
|
-
static get workerId(): number;
|
|
15
|
-
static on(event: string, listener: (...args: any[]) => void): void;
|
|
16
|
-
static send(message: MessageBody): void;
|
|
17
|
-
static kill(): void;
|
|
18
|
-
static gracefulExit(options: Options): void;
|
|
19
13
|
}
|
|
20
14
|
declare class AppProcessUtils extends BaseAppUtils {
|
|
21
15
|
fork(): this;
|
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import { terminate } from "../../../terminate.js";
|
|
2
2
|
import { BaseAppUtils, BaseAppWorker } from "../../base/app.js";
|
|
3
|
-
import { debuglog } from "node:util";
|
|
4
|
-
import { graceful } from "graceful-process";
|
|
5
3
|
import { sendmessage } from "sendmessage";
|
|
6
4
|
import cluster from "node:cluster";
|
|
7
5
|
import { cfork } from "cfork";
|
|
8
6
|
|
|
9
7
|
//#region src/utils/mode/impl/process/app.ts
|
|
10
|
-
const debug = debuglog("egg/cluster/utils/mode/impl/process/app");
|
|
11
8
|
var AppProcessWorker = class extends BaseAppWorker {
|
|
12
9
|
get id() {
|
|
13
10
|
return this.instance.id;
|
|
@@ -27,28 +24,6 @@ var AppProcessWorker = class extends BaseAppWorker {
|
|
|
27
24
|
clean() {
|
|
28
25
|
this.instance.removeAllListeners();
|
|
29
26
|
}
|
|
30
|
-
static get workerId() {
|
|
31
|
-
return process.pid;
|
|
32
|
-
}
|
|
33
|
-
static on(event, listener) {
|
|
34
|
-
process.on(event, listener);
|
|
35
|
-
}
|
|
36
|
-
static send(message) {
|
|
37
|
-
message.senderWorkerId = String(process.pid);
|
|
38
|
-
if (message.action === "app-start" && message.reusePort) {
|
|
39
|
-
debug("send app-start message with reusePort, use cluster.worker.send()");
|
|
40
|
-
cluster.worker.send(message);
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
process.send(message);
|
|
44
|
-
}
|
|
45
|
-
static kill() {
|
|
46
|
-
process.exitCode = 1;
|
|
47
|
-
process.kill(process.pid);
|
|
48
|
-
}
|
|
49
|
-
static gracefulExit(options) {
|
|
50
|
-
graceful(options);
|
|
51
|
-
}
|
|
52
27
|
};
|
|
53
28
|
var AppProcessUtils = class extends BaseAppUtils {
|
|
54
29
|
fork() {
|
|
@@ -56,8 +31,14 @@ var AppProcessUtils = class extends BaseAppUtils {
|
|
|
56
31
|
this.startSuccessCount = 0;
|
|
57
32
|
const args = [JSON.stringify(this.options)];
|
|
58
33
|
this.log("[master] start appWorker with args %j (process)", args);
|
|
34
|
+
const execArgv = this.options.appSnapshotBlob ? [
|
|
35
|
+
...process.execArgv,
|
|
36
|
+
"--snapshot-blob",
|
|
37
|
+
this.options.appSnapshotBlob
|
|
38
|
+
] : void 0;
|
|
59
39
|
cfork({
|
|
60
|
-
exec: this.getAppWorkerFile(),
|
|
40
|
+
exec: this.options.appWorkerFile || this.getAppWorkerFile(),
|
|
41
|
+
...execArgv ? { execArgv } : {},
|
|
61
42
|
args,
|
|
62
43
|
silent: false,
|
|
63
44
|
count: this.options.workers,
|
|
@@ -121,4 +102,4 @@ var AppProcessUtils = class extends BaseAppUtils {
|
|
|
121
102
|
};
|
|
122
103
|
|
|
123
104
|
//#endregion
|
|
124
|
-
export { AppProcessUtils
|
|
105
|
+
export { AppProcessUtils };
|
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
import { BaseAgentUtils, BaseAgentWorker } from "../../base/agent.js";
|
|
2
2
|
import { MessageBody } from "../../../messenger.js";
|
|
3
3
|
import { Worker } from "node:worker_threads";
|
|
4
|
-
import { Options } from "graceful-process";
|
|
5
4
|
|
|
6
5
|
//#region src/utils/mode/impl/worker_threads/agent.d.ts
|
|
7
6
|
declare class AgentThreadWorker extends BaseAgentWorker<Worker> {
|
|
8
7
|
get workerId(): number;
|
|
9
8
|
send(message: MessageBody): void;
|
|
10
|
-
static send(message: MessageBody): void;
|
|
11
|
-
static kill(): void;
|
|
12
|
-
static gracefulExit(options: Options): void;
|
|
13
9
|
}
|
|
14
10
|
declare class AgentThreadUtils extends BaseAgentUtils {
|
|
15
11
|
#private;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { ClusterAgentWorkerError } from "../../../../error/ClusterAgentWorkerError.js";
|
|
2
2
|
import { BaseAgentUtils, BaseAgentWorker } from "../../base/agent.js";
|
|
3
3
|
import workerThreads from "node:worker_threads";
|
|
4
|
-
import "graceful-process";
|
|
5
4
|
|
|
6
5
|
//#region src/utils/mode/impl/worker_threads/agent.ts
|
|
7
6
|
var AgentThreadWorker = class extends BaseAgentWorker {
|
|
@@ -11,20 +10,6 @@ var AgentThreadWorker = class extends BaseAgentWorker {
|
|
|
11
10
|
send(message) {
|
|
12
11
|
this.instance.postMessage(message);
|
|
13
12
|
}
|
|
14
|
-
static send(message) {
|
|
15
|
-
message.senderWorkerId = String(workerThreads.threadId);
|
|
16
|
-
workerThreads.parentPort.postMessage(message);
|
|
17
|
-
}
|
|
18
|
-
static kill() {
|
|
19
|
-
process.exit(1);
|
|
20
|
-
}
|
|
21
|
-
static gracefulExit(options) {
|
|
22
|
-
const { beforeExit } = options;
|
|
23
|
-
process.on("exit", async (code) => {
|
|
24
|
-
if (typeof beforeExit === "function") await beforeExit();
|
|
25
|
-
process.exit(code);
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
13
|
};
|
|
29
14
|
var AgentThreadUtils = class extends BaseAgentUtils {
|
|
30
15
|
#worker;
|
|
@@ -33,7 +18,7 @@ var AgentThreadUtils = class extends BaseAgentUtils {
|
|
|
33
18
|
fork() {
|
|
34
19
|
this.startTime = Date.now();
|
|
35
20
|
const argv = [JSON.stringify(this.options)];
|
|
36
|
-
const agentPath = this.getAgentWorkerFile();
|
|
21
|
+
const agentPath = this.options.agentWorkerFile || this.getAgentWorkerFile();
|
|
37
22
|
const worker = this.#worker = new workerThreads.Worker(agentPath, { argv });
|
|
38
23
|
const agentWorker = this.instance = new AgentThreadWorker(worker);
|
|
39
24
|
this.emit("agent_forked", agentWorker);
|
|
@@ -76,4 +61,4 @@ var AgentThreadUtils = class extends BaseAgentUtils {
|
|
|
76
61
|
};
|
|
77
62
|
|
|
78
63
|
//#endregion
|
|
79
|
-
export { AgentThreadUtils
|
|
64
|
+
export { AgentThreadUtils };
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { BaseAppUtils, BaseAppWorker } from "../../base/app.js";
|
|
2
2
|
import { MessageBody } from "../../../messenger.js";
|
|
3
3
|
import { Worker } from "node:worker_threads";
|
|
4
|
-
import { Options } from "graceful-process";
|
|
5
4
|
|
|
6
5
|
//#region src/utils/mode/impl/worker_threads/app.d.ts
|
|
7
6
|
declare class AppThreadWorker extends BaseAppWorker<Worker> {
|
|
@@ -15,11 +14,6 @@ declare class AppThreadWorker extends BaseAppWorker<Worker> {
|
|
|
15
14
|
get exitCode(): number;
|
|
16
15
|
send(message: MessageBody): void;
|
|
17
16
|
clean(): void;
|
|
18
|
-
static get workerId(): number;
|
|
19
|
-
static on(event: string, listener: (...args: any[]) => void): void;
|
|
20
|
-
static send(message: MessageBody): void;
|
|
21
|
-
static kill(): void;
|
|
22
|
-
static gracefulExit(options: Options): void;
|
|
23
17
|
}
|
|
24
18
|
declare class AppThreadUtils extends BaseAppUtils {
|
|
25
19
|
#private;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BaseAppUtils, BaseAppWorker } from "../../base/app.js";
|
|
2
|
-
import { Worker
|
|
2
|
+
import { Worker } from "node:worker_threads";
|
|
3
3
|
import { setTimeout } from "node:timers/promises";
|
|
4
4
|
|
|
5
5
|
//#region src/utils/mode/impl/worker_threads/app.ts
|
|
@@ -34,25 +34,6 @@ var AppThreadWorker = class extends BaseAppWorker {
|
|
|
34
34
|
clean() {
|
|
35
35
|
this.instance.removeAllListeners();
|
|
36
36
|
}
|
|
37
|
-
static get workerId() {
|
|
38
|
-
return threadId;
|
|
39
|
-
}
|
|
40
|
-
static on(event, listener) {
|
|
41
|
-
parentPort.on(event, listener);
|
|
42
|
-
}
|
|
43
|
-
static send(message) {
|
|
44
|
-
message.senderWorkerId = String(threadId);
|
|
45
|
-
parentPort.postMessage(message);
|
|
46
|
-
}
|
|
47
|
-
static kill() {
|
|
48
|
-
process.exit(1);
|
|
49
|
-
}
|
|
50
|
-
static gracefulExit(options) {
|
|
51
|
-
process.on("exit", async (code) => {
|
|
52
|
-
if (typeof options.beforeExit === "function") await options.beforeExit();
|
|
53
|
-
process.exit(code);
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
37
|
};
|
|
57
38
|
var AppThreadUtils = class extends BaseAppUtils {
|
|
58
39
|
#workers = [];
|
|
@@ -103,11 +84,12 @@ var AppThreadUtils = class extends BaseAppUtils {
|
|
|
103
84
|
fork() {
|
|
104
85
|
this.startTime = Date.now();
|
|
105
86
|
this.startSuccessCount = 0;
|
|
87
|
+
const appWorkerFile = this.options.appWorkerFile || this.getAppWorkerFile();
|
|
106
88
|
if (this.options.reusePort) {
|
|
107
89
|
if (!this.options.port) throw new Error("options.port must be specified when reusePort is enabled");
|
|
108
90
|
for (let i = 0; i < this.options.workers; i++) {
|
|
109
91
|
const argv = [JSON.stringify(this.options)];
|
|
110
|
-
this.#forkSingle(
|
|
92
|
+
this.#forkSingle(appWorkerFile, { argv }, i + 1);
|
|
111
93
|
}
|
|
112
94
|
} else {
|
|
113
95
|
const ports = this.options.ports ?? [];
|
|
@@ -117,7 +99,7 @@ var AppThreadUtils = class extends BaseAppUtils {
|
|
|
117
99
|
do {
|
|
118
100
|
const options = Object.assign({}, this.options, { port: ports[i] });
|
|
119
101
|
const argv = [JSON.stringify(options)];
|
|
120
|
-
this.#forkSingle(
|
|
102
|
+
this.#forkSingle(appWorkerFile, { argv }, ++i);
|
|
121
103
|
} while (i < ports.length);
|
|
122
104
|
}
|
|
123
105
|
return this;
|
|
@@ -133,4 +115,4 @@ var AppThreadUtils = class extends BaseAppUtils {
|
|
|
133
115
|
};
|
|
134
116
|
|
|
135
117
|
//#endregion
|
|
136
|
-
export { AppThreadUtils
|
|
118
|
+
export { AppThreadUtils };
|
package/dist/utils/options.d.ts
CHANGED
|
@@ -61,6 +61,22 @@ interface ClusterOptions {
|
|
|
61
61
|
*/
|
|
62
62
|
startMode?: ClusterStartMode;
|
|
63
63
|
/**
|
|
64
|
+
* custom app worker file
|
|
65
|
+
*/
|
|
66
|
+
appWorkerFile?: string;
|
|
67
|
+
/**
|
|
68
|
+
* custom agent worker file
|
|
69
|
+
*/
|
|
70
|
+
agentWorkerFile?: string;
|
|
71
|
+
/**
|
|
72
|
+
* V8 startup snapshot blob used to restore app workers, only available in process mode
|
|
73
|
+
*/
|
|
74
|
+
appSnapshotBlob?: string;
|
|
75
|
+
/**
|
|
76
|
+
* V8 startup snapshot blob used to restore the agent worker, only available in process mode
|
|
77
|
+
*/
|
|
78
|
+
agentSnapshotBlob?: string;
|
|
79
|
+
/**
|
|
64
80
|
* startup port of each app worker, such as: `[7001, 7002, 7003]`, only effects when the startMode is `'worker_threads'`
|
|
65
81
|
*/
|
|
66
82
|
ports?: number[];
|
package/dist/utils/options.js
CHANGED
|
@@ -46,6 +46,25 @@ async function parseOptions(options) {
|
|
|
46
46
|
if (options.require) {
|
|
47
47
|
if (typeof options.require === "string") options.require = [options.require];
|
|
48
48
|
}
|
|
49
|
+
for (const optionName of ["appWorkerFile", "agentWorkerFile"]) {
|
|
50
|
+
const workerFile = options[optionName];
|
|
51
|
+
if (!workerFile) {
|
|
52
|
+
options[optionName] = void 0;
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
options[optionName] = path.resolve(options.baseDir, workerFile);
|
|
56
|
+
assert(fs.existsSync(options[optionName]), `options.${optionName} file should exist: ${options[optionName]}`);
|
|
57
|
+
}
|
|
58
|
+
for (const optionName of ["appSnapshotBlob", "agentSnapshotBlob"]) {
|
|
59
|
+
const snapshotBlob = options[optionName];
|
|
60
|
+
if (!snapshotBlob) {
|
|
61
|
+
options[optionName] = void 0;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
options[optionName] = path.resolve(options.baseDir, snapshotBlob);
|
|
65
|
+
assert(fs.existsSync(options[optionName]), `options.${optionName} file should exist: ${options[optionName]}`);
|
|
66
|
+
assert(options.startMode !== "worker_threads", `options.${optionName} only supports startMode "process"`);
|
|
67
|
+
}
|
|
49
68
|
if (process.env.NODE_ENV === "production") process.env.NO_DEPRECATION = "*";
|
|
50
69
|
const isDebug = process.execArgv.some((argv) => argv.includes("--debug") || argv.includes("--inspect"));
|
|
51
70
|
if (isDebug) options.isDebug = isDebug;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { MessageBody } from "../utils/messenger.js";
|
|
2
|
+
import { EggConsoleLogger } from "egg-logger";
|
|
3
|
+
import { Options } from "graceful-process";
|
|
4
|
+
|
|
5
|
+
//#region src/worker_protocol/agent.d.ts
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Transport used by the agent-worker protocol. Process and worker-thread
|
|
9
|
+
* entries provide different implementations of this interface.
|
|
10
|
+
*/
|
|
11
|
+
interface AgentWorkerIO {
|
|
12
|
+
send(message: MessageBody): void;
|
|
13
|
+
kill(): void;
|
|
14
|
+
gracefulExit(options: Options): void;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Run the agent-worker side of the Egg cluster protocol on an already
|
|
18
|
+
* constructed agent: report `agent-start` on readiness, exit on start error,
|
|
19
|
+
* and wire graceful exit.
|
|
20
|
+
*/
|
|
21
|
+
declare function startAgentWorker(agent: any, io: AgentWorkerIO, consoleLogger?: EggConsoleLogger): void;
|
|
22
|
+
//#endregion
|
|
23
|
+
export { AgentWorkerIO, startAgentWorker };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { EggConsoleLogger } from "egg-logger";
|
|
2
|
+
|
|
3
|
+
//#region src/worker_protocol/agent.ts
|
|
4
|
+
/**
|
|
5
|
+
* Run the agent-worker side of the Egg cluster protocol on an already
|
|
6
|
+
* constructed agent: report `agent-start` on readiness, exit on start error,
|
|
7
|
+
* and wire graceful exit.
|
|
8
|
+
*/
|
|
9
|
+
function startAgentWorker(agent, io, consoleLogger = new EggConsoleLogger({ level: process.env.EGG_AGENT_WORKER_LOGGER_LEVEL })) {
|
|
10
|
+
function startErrorHandler(err) {
|
|
11
|
+
consoleLogger.error(err);
|
|
12
|
+
consoleLogger.error("[agent_worker] start error, exiting with code:1");
|
|
13
|
+
io.kill();
|
|
14
|
+
}
|
|
15
|
+
agent.once("error", startErrorHandler);
|
|
16
|
+
agent.ready((err) => {
|
|
17
|
+
if (err) return;
|
|
18
|
+
agent.removeListener("error", startErrorHandler);
|
|
19
|
+
io.send({
|
|
20
|
+
action: "agent-start",
|
|
21
|
+
to: "master"
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
io.gracefulExit({
|
|
25
|
+
logger: consoleLogger,
|
|
26
|
+
label: "agent_worker",
|
|
27
|
+
beforeExit: () => agent.close()
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
//#endregion
|
|
32
|
+
export { startAgentWorker };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { AgentWorkerIO } from "./agent.js";
|
|
2
|
+
import { EggConsoleLogger } from "egg-logger";
|
|
3
|
+
|
|
4
|
+
//#region src/worker_protocol/app.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Transport used by the app-worker protocol. It extends the agent surface
|
|
8
|
+
* with app-specific worker identity and sticky-session message handling.
|
|
9
|
+
*/
|
|
10
|
+
interface AppWorkerIO extends AgentWorkerIO {
|
|
11
|
+
readonly workerId: number | string;
|
|
12
|
+
on(event: string, listener: (...args: any[]) => void): void;
|
|
13
|
+
}
|
|
14
|
+
interface AppWorkerProtocolOptions {
|
|
15
|
+
port?: number;
|
|
16
|
+
debugPort?: number;
|
|
17
|
+
https?: object;
|
|
18
|
+
sticky?: boolean;
|
|
19
|
+
stickyWorkerPort?: number;
|
|
20
|
+
reusePort?: boolean;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Run the app-worker side of the Egg cluster protocol on an already
|
|
24
|
+
* constructed application: wait for readiness, create the HTTP(S) server
|
|
25
|
+
* (sticky / reusePort / debug port variants), report `realport` and
|
|
26
|
+
* `app-start` to the master, and wire graceful exit.
|
|
27
|
+
*/
|
|
28
|
+
declare function startAppWorker(app: any, options: AppWorkerProtocolOptions, io: AppWorkerIO, consoleLogger?: EggConsoleLogger): void;
|
|
29
|
+
//#endregion
|
|
30
|
+
export { AppWorkerIO, AppWorkerProtocolOptions, startAppWorker };
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import { debuglog } from "node:util";
|
|
4
|
+
import { EggConsoleLogger } from "egg-logger";
|
|
5
|
+
import { createServer } from "node:http";
|
|
6
|
+
import { createServer as createServer$1 } from "node:https";
|
|
7
|
+
|
|
8
|
+
//#region src/worker_protocol/app.ts
|
|
9
|
+
const debug = debuglog("egg/cluster/worker_protocol/app");
|
|
10
|
+
const REUSE_PORT_SUPPORTED_PLATFORMS = [
|
|
11
|
+
"linux",
|
|
12
|
+
"freebsd",
|
|
13
|
+
"sunos",
|
|
14
|
+
"aix"
|
|
15
|
+
];
|
|
16
|
+
/**
|
|
17
|
+
* Run the app-worker side of the Egg cluster protocol on an already
|
|
18
|
+
* constructed application: wait for readiness, create the HTTP(S) server
|
|
19
|
+
* (sticky / reusePort / debug port variants), report `realport` and
|
|
20
|
+
* `app-start` to the master, and wire graceful exit.
|
|
21
|
+
*/
|
|
22
|
+
function startAppWorker(app, options, io, consoleLogger = new EggConsoleLogger({ level: process.env.EGG_APP_WORKER_LOGGER_LEVEL })) {
|
|
23
|
+
function exitProcess() {
|
|
24
|
+
io.kill();
|
|
25
|
+
}
|
|
26
|
+
function startTimeoutHandler() {
|
|
27
|
+
consoleLogger.error("[app_worker] start timeout, exiting with code:1");
|
|
28
|
+
exitProcess();
|
|
29
|
+
}
|
|
30
|
+
app.once("startTimeout", startTimeoutHandler);
|
|
31
|
+
app.ready(startServer);
|
|
32
|
+
function startServer(err) {
|
|
33
|
+
if (err) {
|
|
34
|
+
consoleLogger.error(err);
|
|
35
|
+
consoleLogger.error("[app_worker] start error, exiting with code:1");
|
|
36
|
+
exitProcess();
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const clusterConfig = app.config.cluster ?? {};
|
|
40
|
+
const listenConfig = clusterConfig.listen ?? {};
|
|
41
|
+
const httpsOptions = {
|
|
42
|
+
...clusterConfig.https,
|
|
43
|
+
...options.https
|
|
44
|
+
};
|
|
45
|
+
const port = app.options.port = options.port || listenConfig.port;
|
|
46
|
+
const debugPort = options.debugPort;
|
|
47
|
+
const protocol = httpsOptions.key && httpsOptions.cert ? "https" : "http";
|
|
48
|
+
let reusePort = options.reusePort ?? listenConfig.reusePort ?? false;
|
|
49
|
+
if (reusePort && !REUSE_PORT_SUPPORTED_PLATFORMS.includes(os.platform())) {
|
|
50
|
+
reusePort = false;
|
|
51
|
+
debug("[app_worker:%s] platform %s is not supported for reusePort, set reusePort to false", process.pid, os.platform());
|
|
52
|
+
}
|
|
53
|
+
debug("[app_worker:%s] listenConfig: %j, real port: %o, protocol: %o, debugPort: %o, reusePort: %o", process.pid, listenConfig, port, protocol, debugPort, reusePort);
|
|
54
|
+
io.send({
|
|
55
|
+
to: "master",
|
|
56
|
+
action: "realport",
|
|
57
|
+
data: {
|
|
58
|
+
port,
|
|
59
|
+
protocol
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
app.removeListener("startTimeout", startTimeoutHandler);
|
|
63
|
+
let server;
|
|
64
|
+
let debugPortServer;
|
|
65
|
+
if (protocol === "https") {
|
|
66
|
+
httpsOptions.key = fs.readFileSync(httpsOptions.key);
|
|
67
|
+
httpsOptions.cert = fs.readFileSync(httpsOptions.cert);
|
|
68
|
+
httpsOptions.ca = httpsOptions.ca && fs.readFileSync(httpsOptions.ca);
|
|
69
|
+
server = createServer$1(httpsOptions, app.callback());
|
|
70
|
+
if (debugPort) debugPortServer = createServer(app.callback());
|
|
71
|
+
} else {
|
|
72
|
+
server = createServer(app.callback());
|
|
73
|
+
if (debugPort) debugPortServer = server;
|
|
74
|
+
}
|
|
75
|
+
server.once("error", (err$1) => {
|
|
76
|
+
consoleLogger.error("[app_worker] server got error: %s, code: %s", err$1.message, err$1.code);
|
|
77
|
+
exitProcess();
|
|
78
|
+
});
|
|
79
|
+
app.emit("server", server);
|
|
80
|
+
if (options.sticky && options.stickyWorkerPort) {
|
|
81
|
+
server.listen(options.stickyWorkerPort, "127.0.0.1");
|
|
82
|
+
io.on("message", (message, connection) => {
|
|
83
|
+
if (message !== "sticky-session:connection") return;
|
|
84
|
+
server.emit("connection", connection);
|
|
85
|
+
connection.resume();
|
|
86
|
+
});
|
|
87
|
+
} else {
|
|
88
|
+
if (listenConfig.path) server.listen(listenConfig.path);
|
|
89
|
+
else {
|
|
90
|
+
if (typeof port !== "number") {
|
|
91
|
+
consoleLogger.error("[app_worker:%s] port should be number, but got %s(%s)", process.pid, port, typeof port);
|
|
92
|
+
exitProcess();
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (reusePort) {
|
|
96
|
+
const listenOptions = {
|
|
97
|
+
port,
|
|
98
|
+
reusePort
|
|
99
|
+
};
|
|
100
|
+
if (listenConfig.hostname) listenOptions.host = listenConfig.hostname;
|
|
101
|
+
debug("[app_worker:%s] listen with reusePort options %j", process.pid, listenOptions);
|
|
102
|
+
server.listen(listenOptions);
|
|
103
|
+
} else {
|
|
104
|
+
const args = [port];
|
|
105
|
+
if (listenConfig.hostname) args.push(listenConfig.hostname);
|
|
106
|
+
debug("listen options %j", args);
|
|
107
|
+
server.listen(...args);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (debugPortServer) {
|
|
111
|
+
debug("listen on debug port: %s", debugPort);
|
|
112
|
+
debugPortServer.listen(debugPort);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
server.once("listening", () => {
|
|
116
|
+
let address = server.address() || { port };
|
|
117
|
+
if (typeof address === "string") address = {
|
|
118
|
+
address,
|
|
119
|
+
addressType: -1
|
|
120
|
+
};
|
|
121
|
+
debug("[app_worker:%s] listening at %j, reusePort: %o", process.pid, address, reusePort);
|
|
122
|
+
io.send({
|
|
123
|
+
to: "master",
|
|
124
|
+
action: "app-start",
|
|
125
|
+
data: {
|
|
126
|
+
address,
|
|
127
|
+
workerId: io.workerId
|
|
128
|
+
},
|
|
129
|
+
reusePort
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
io.gracefulExit({
|
|
134
|
+
logger: consoleLogger,
|
|
135
|
+
label: "app_worker",
|
|
136
|
+
beforeExit: () => app.close()
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
//#endregion
|
|
141
|
+
export { startAppWorker };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { AppWorkerIO } from "./app.js";
|
|
2
|
+
|
|
3
|
+
//#region src/worker_protocol/process.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Process-backed worker transport shared by the traditional process entries
|
|
7
|
+
* and the egg-bundler worker entry (plain boot or V8 snapshot restore).
|
|
8
|
+
*
|
|
9
|
+
* `node:cluster` is fetched only for the reusePort notification so snapshot
|
|
10
|
+
* construction does not cache the build process's primary/worker flavor.
|
|
11
|
+
*/
|
|
12
|
+
declare function createProcessWorkerIO(): AppWorkerIO;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { createProcessWorkerIO };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { graceful } from "graceful-process";
|
|
2
|
+
|
|
3
|
+
//#region src/worker_protocol/process.ts
|
|
4
|
+
/**
|
|
5
|
+
* Process-backed worker transport shared by the traditional process entries
|
|
6
|
+
* and the egg-bundler worker entry (plain boot or V8 snapshot restore).
|
|
7
|
+
*
|
|
8
|
+
* `node:cluster` is fetched only for the reusePort notification so snapshot
|
|
9
|
+
* construction does not cache the build process's primary/worker flavor.
|
|
10
|
+
*/
|
|
11
|
+
function createProcessWorkerIO() {
|
|
12
|
+
return {
|
|
13
|
+
get workerId() {
|
|
14
|
+
return process.pid;
|
|
15
|
+
},
|
|
16
|
+
send(message) {
|
|
17
|
+
message.senderWorkerId = String(process.pid);
|
|
18
|
+
if (message.action === "app-start" && message.reusePort) {
|
|
19
|
+
process.getBuiltinModule("node:cluster").worker.send(message);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
process.send(message);
|
|
23
|
+
},
|
|
24
|
+
on(event, listener) {
|
|
25
|
+
process.on(event, listener);
|
|
26
|
+
},
|
|
27
|
+
kill() {
|
|
28
|
+
process.exitCode = 1;
|
|
29
|
+
process.kill(process.pid);
|
|
30
|
+
},
|
|
31
|
+
gracefulExit(options) {
|
|
32
|
+
graceful(options);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
//#endregion
|
|
38
|
+
export { createProcessWorkerIO };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { AppWorkerIO } from "./app.js";
|
|
2
|
+
|
|
3
|
+
//#region src/worker_protocol/worker-thread.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Worker-thread-backed transport shared by the standard worker entries and
|
|
7
|
+
* generated bundle entries.
|
|
8
|
+
*/
|
|
9
|
+
declare function createWorkerThreadIO(): AppWorkerIO;
|
|
10
|
+
//#endregion
|
|
11
|
+
export { createWorkerThreadIO };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { parentPort, threadId } from "node:worker_threads";
|
|
2
|
+
|
|
3
|
+
//#region src/worker_protocol/worker-thread.ts
|
|
4
|
+
/**
|
|
5
|
+
* Worker-thread-backed transport shared by the standard worker entries and
|
|
6
|
+
* generated bundle entries.
|
|
7
|
+
*/
|
|
8
|
+
function createWorkerThreadIO() {
|
|
9
|
+
const port = parentPort;
|
|
10
|
+
if (!port) throw new Error("createWorkerThreadIO() must be called inside a worker thread");
|
|
11
|
+
return {
|
|
12
|
+
workerId: threadId,
|
|
13
|
+
send(message) {
|
|
14
|
+
message.senderWorkerId = String(threadId);
|
|
15
|
+
port.postMessage(message);
|
|
16
|
+
},
|
|
17
|
+
on(event, listener) {
|
|
18
|
+
port.on(event, listener);
|
|
19
|
+
},
|
|
20
|
+
kill() {
|
|
21
|
+
process.exit(1);
|
|
22
|
+
},
|
|
23
|
+
gracefulExit(options) {
|
|
24
|
+
const { beforeExit } = options;
|
|
25
|
+
process.on("exit", async (code) => {
|
|
26
|
+
if (typeof beforeExit === "function") await beforeExit();
|
|
27
|
+
process.exit(code);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
//#endregion
|
|
34
|
+
export { createWorkerThreadIO };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { AgentWorkerIO, startAgentWorker } from "./worker_protocol/agent.js";
|
|
2
|
+
import { AppWorkerIO, AppWorkerProtocolOptions, startAppWorker } from "./worker_protocol/app.js";
|
|
3
|
+
import { createProcessWorkerIO } from "./worker_protocol/process.js";
|
|
4
|
+
import { createWorkerThreadIO } from "./worker_protocol/worker-thread.js";
|
|
5
|
+
export { type AgentWorkerIO, type AppWorkerIO, type AppWorkerProtocolOptions, createProcessWorkerIO, createWorkerThreadIO, startAgentWorker, startAppWorker };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { startAgentWorker } from "./worker_protocol/agent.js";
|
|
2
|
+
import { createProcessWorkerIO } from "./worker_protocol/process.js";
|
|
3
|
+
import { createWorkerThreadIO } from "./worker_protocol/worker-thread.js";
|
|
4
|
+
import { startAppWorker } from "./worker_protocol/app.js";
|
|
5
|
+
|
|
6
|
+
export { createProcessWorkerIO, createWorkerThreadIO, startAgentWorker, startAppWorker };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eggjs/cluster",
|
|
3
|
-
"version": "4.0.2-beta.
|
|
3
|
+
"version": "4.0.2-beta.27",
|
|
4
4
|
"description": "cluster manager for egg",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cluster",
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
".": "./dist/index.js",
|
|
30
30
|
"./agent_worker": "./dist/agent_worker.js",
|
|
31
31
|
"./app_worker": "./dist/app_worker.js",
|
|
32
|
+
"./worker_protocol": "./dist/worker_protocol.js",
|
|
32
33
|
"./package.json": "./package.json"
|
|
33
34
|
},
|
|
34
35
|
"publishConfig": {
|
|
@@ -37,6 +38,7 @@
|
|
|
37
38
|
".": "./dist/index.js",
|
|
38
39
|
"./agent_worker": "./dist/agent_worker.js",
|
|
39
40
|
"./app_worker": "./dist/app_worker.js",
|
|
41
|
+
"./worker_protocol": "./dist/worker_protocol.js",
|
|
40
42
|
"./package.json": "./package.json"
|
|
41
43
|
}
|
|
42
44
|
},
|
|
@@ -46,7 +48,7 @@
|
|
|
46
48
|
"test": "vitest run"
|
|
47
49
|
},
|
|
48
50
|
"dependencies": {
|
|
49
|
-
"@eggjs/utils": "5.0.2-beta.
|
|
51
|
+
"@eggjs/utils": "5.0.2-beta.27",
|
|
50
52
|
"@fengmk2/ps-tree": "^2.0.1",
|
|
51
53
|
"cfork": "^2.0.0",
|
|
52
54
|
"cluster-reload": "^2.0.0",
|
|
@@ -59,10 +61,10 @@
|
|
|
59
61
|
"utility": "^2.5.0"
|
|
60
62
|
},
|
|
61
63
|
"devDependencies": {
|
|
62
|
-
"@eggjs/errors": "3.0.2-beta.
|
|
63
|
-
"@eggjs/mock": "7.0.2-beta.
|
|
64
|
-
"@eggjs/supertest": "9.0.2-beta.
|
|
65
|
-
"@eggjs/tsconfig": "3.1.2-beta.
|
|
64
|
+
"@eggjs/errors": "3.0.2-beta.27",
|
|
65
|
+
"@eggjs/mock": "7.0.2-beta.27",
|
|
66
|
+
"@eggjs/supertest": "9.0.2-beta.27",
|
|
67
|
+
"@eggjs/tsconfig": "3.1.2-beta.27",
|
|
66
68
|
"address": "2",
|
|
67
69
|
"coffee": "5",
|
|
68
70
|
"tsdown": "^0.18.2",
|