@eggjs/cluster 4.0.0-beta.20 → 4.0.0-beta.21
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.d.ts +1 -1
- package/dist/agent_worker.js +64 -51
- package/dist/app_worker.d.ts +1 -1
- package/dist/app_worker.js +166 -128
- package/dist/dirname.d.ts +1 -0
- package/dist/dirname.js +11 -0
- package/dist/error/ClusterAgentWorkerError.d.ts +10 -0
- package/dist/error/ClusterAgentWorkerError.js +19 -0
- package/dist/error/ClusterWorkerExceptionError.d.ts +7 -0
- package/dist/error/ClusterWorkerExceptionError.js +14 -0
- package/dist/error/index.d.ts +2 -0
- package/dist/error/index.js +3 -0
- package/dist/index.d.ts +5 -445
- package/dist/index.js +17 -709
- package/dist/master.d.ts +90 -0
- package/dist/master.js +553 -0
- package/dist/utils/messenger.d.ts +92 -0
- package/dist/utils/messenger.js +179 -0
- package/dist/utils/mode/base/agent.d.ts +38 -0
- package/dist/utils/mode/base/agent.js +65 -0
- package/dist/utils/mode/base/app.d.ts +48 -0
- package/dist/utils/mode/base/app.js +80 -0
- package/dist/utils/mode/impl/process/agent.d.ts +18 -0
- package/dist/utils/mode/impl/process/agent.js +103 -0
- package/dist/utils/mode/impl/process/app.d.ts +21 -0
- package/dist/utils/mode/impl/process/app.js +119 -0
- package/dist/utils/mode/impl/worker_threads/agent.d.ts +18 -0
- package/dist/utils/mode/impl/worker_threads/agent.js +84 -0
- package/dist/utils/mode/impl/worker_threads/app.d.ts +26 -0
- package/dist/utils/mode/impl/worker_threads/app.js +137 -0
- package/dist/utils/options.d.ts +80 -0
- package/dist/utils/options.js +81 -0
- package/dist/utils/terminate.d.ts +6 -0
- package/dist/utils/terminate.js +81 -0
- package/dist/utils/worker_manager.d.ts +25 -0
- package/dist/utils/worker_manager.js +74 -0
- package/package.json +6 -6
- package/dist/agent-griHEaCW.js +0 -246
- package/dist/app-5Was1vub.js +0 -315
- package/dist/terminate-w3g0oQgq.js +0 -71
package/dist/app-5Was1vub.js
DELETED
|
@@ -1,315 +0,0 @@
|
|
|
1
|
-
import { getSrcDirname, terminate } from "./terminate-w3g0oQgq.js";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { existsSync } from "node:fs";
|
|
4
|
-
import { EventEmitter } from "node:events";
|
|
5
|
-
import { Worker, parentPort, threadId } from "node:worker_threads";
|
|
6
|
-
import { sendmessage } from "sendmessage";
|
|
7
|
-
import { graceful } from "graceful-process";
|
|
8
|
-
import { setTimeout } from "node:timers/promises";
|
|
9
|
-
import cluster from "node:cluster";
|
|
10
|
-
import { cfork } from "cfork";
|
|
11
|
-
|
|
12
|
-
//#region src/utils/mode/base/app.ts
|
|
13
|
-
var BaseAppWorker = class {
|
|
14
|
-
instance;
|
|
15
|
-
constructor(instance) {
|
|
16
|
-
this.instance = instance;
|
|
17
|
-
}
|
|
18
|
-
get state() {
|
|
19
|
-
return Reflect.get(this.instance, "state");
|
|
20
|
-
}
|
|
21
|
-
set state(state) {
|
|
22
|
-
Reflect.set(this.instance, "state", state);
|
|
23
|
-
}
|
|
24
|
-
get disableRefork() {
|
|
25
|
-
return Reflect.get(this.instance, "disableRefork");
|
|
26
|
-
}
|
|
27
|
-
set disableRefork(disableRefork) {
|
|
28
|
-
Reflect.set(this.instance, "disableRefork", disableRefork);
|
|
29
|
-
}
|
|
30
|
-
get isDevReload() {
|
|
31
|
-
return Reflect.get(this.instance, "isDevReload");
|
|
32
|
-
}
|
|
33
|
-
set isDevReload(isDevReload) {
|
|
34
|
-
Reflect.set(this.instance, "isDevReload", isDevReload);
|
|
35
|
-
}
|
|
36
|
-
clean() {
|
|
37
|
-
throw new Error("BaseAppWorker should implement clean.");
|
|
38
|
-
}
|
|
39
|
-
static get workerId() {
|
|
40
|
-
throw new Error("BaseAppWorker should implement workerId.");
|
|
41
|
-
}
|
|
42
|
-
static on(..._args) {
|
|
43
|
-
throw new Error("BaseAppWorker should implement on.");
|
|
44
|
-
}
|
|
45
|
-
static send(_message) {
|
|
46
|
-
throw new Error("BaseAgentWorker should implement send.");
|
|
47
|
-
}
|
|
48
|
-
static kill() {
|
|
49
|
-
throw new Error("BaseAppWorker should implement kill.");
|
|
50
|
-
}
|
|
51
|
-
static gracefulExit(_options) {
|
|
52
|
-
throw new Error("BaseAgentWorker should implement gracefulExit.");
|
|
53
|
-
}
|
|
54
|
-
};
|
|
55
|
-
var BaseAppUtils = class extends EventEmitter {
|
|
56
|
-
options;
|
|
57
|
-
messenger;
|
|
58
|
-
log;
|
|
59
|
-
logger;
|
|
60
|
-
isProduction;
|
|
61
|
-
startTime = 0;
|
|
62
|
-
startSuccessCount = 0;
|
|
63
|
-
isAllWorkerStarted = false;
|
|
64
|
-
constructor(options, { log, logger, messenger, isProduction }) {
|
|
65
|
-
super();
|
|
66
|
-
this.options = options;
|
|
67
|
-
this.log = log;
|
|
68
|
-
this.logger = logger;
|
|
69
|
-
this.messenger = messenger;
|
|
70
|
-
this.isProduction = isProduction;
|
|
71
|
-
}
|
|
72
|
-
getAppWorkerFile() {
|
|
73
|
-
let appWorkerFile = path.join(getSrcDirname(), "app_worker.js");
|
|
74
|
-
if (!existsSync(appWorkerFile)) appWorkerFile = path.join(getSrcDirname(), "app_worker.ts");
|
|
75
|
-
return appWorkerFile;
|
|
76
|
-
}
|
|
77
|
-
fork() {
|
|
78
|
-
throw new Error("BaseApp should implement fork.");
|
|
79
|
-
}
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
//#endregion
|
|
83
|
-
//#region src/utils/mode/impl/process/app.ts
|
|
84
|
-
var AppProcessWorker = class extends BaseAppWorker {
|
|
85
|
-
get id() {
|
|
86
|
-
return this.instance.id;
|
|
87
|
-
}
|
|
88
|
-
get workerId() {
|
|
89
|
-
return this.instance.process.pid;
|
|
90
|
-
}
|
|
91
|
-
get exitedAfterDisconnect() {
|
|
92
|
-
return this.instance.exitedAfterDisconnect;
|
|
93
|
-
}
|
|
94
|
-
get exitCode() {
|
|
95
|
-
return this.instance.process.exitCode;
|
|
96
|
-
}
|
|
97
|
-
send(message) {
|
|
98
|
-
sendmessage(this.instance, message);
|
|
99
|
-
}
|
|
100
|
-
clean() {
|
|
101
|
-
this.instance.removeAllListeners();
|
|
102
|
-
}
|
|
103
|
-
static get workerId() {
|
|
104
|
-
return process.pid;
|
|
105
|
-
}
|
|
106
|
-
static on(event, listener) {
|
|
107
|
-
process.on(event, listener);
|
|
108
|
-
}
|
|
109
|
-
static send(message) {
|
|
110
|
-
message.senderWorkerId = String(process.pid);
|
|
111
|
-
process.send(message);
|
|
112
|
-
}
|
|
113
|
-
static kill() {
|
|
114
|
-
process.exitCode = 1;
|
|
115
|
-
process.kill(process.pid);
|
|
116
|
-
}
|
|
117
|
-
static gracefulExit(options) {
|
|
118
|
-
graceful(options);
|
|
119
|
-
}
|
|
120
|
-
};
|
|
121
|
-
var AppProcessUtils = class extends BaseAppUtils {
|
|
122
|
-
fork() {
|
|
123
|
-
this.startTime = Date.now();
|
|
124
|
-
this.startSuccessCount = 0;
|
|
125
|
-
const args = [JSON.stringify(this.options)];
|
|
126
|
-
this.log("[master] start appWorker with args %j (process)", args);
|
|
127
|
-
cfork({
|
|
128
|
-
exec: this.getAppWorkerFile(),
|
|
129
|
-
args,
|
|
130
|
-
silent: false,
|
|
131
|
-
count: this.options.workers,
|
|
132
|
-
refork: this.isProduction,
|
|
133
|
-
windowsHide: process.platform === "win32"
|
|
134
|
-
});
|
|
135
|
-
let debugPort = process.debugPort;
|
|
136
|
-
cluster.on("fork", (worker) => {
|
|
137
|
-
const appWorker = new AppProcessWorker(worker);
|
|
138
|
-
this.emit("worker_forked", appWorker);
|
|
139
|
-
appWorker.disableRefork = true;
|
|
140
|
-
worker.on("message", (msg) => {
|
|
141
|
-
if (typeof msg === "string") msg = {
|
|
142
|
-
action: msg,
|
|
143
|
-
data: msg
|
|
144
|
-
};
|
|
145
|
-
msg.from = "app";
|
|
146
|
-
this.messenger.send(msg);
|
|
147
|
-
});
|
|
148
|
-
this.log("[master] app_worker#%s:%s start, state: %s, current workers: %j", appWorker.id, appWorker.workerId, appWorker.state, Object.keys(cluster.workers));
|
|
149
|
-
if (this.options.isDebug) {
|
|
150
|
-
debugPort++;
|
|
151
|
-
this.messenger.send({
|
|
152
|
-
to: "parent",
|
|
153
|
-
from: "app",
|
|
154
|
-
action: "debug",
|
|
155
|
-
data: {
|
|
156
|
-
debugPort,
|
|
157
|
-
pid: appWorker.workerId,
|
|
158
|
-
workerId: appWorker.workerId
|
|
159
|
-
}
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
});
|
|
163
|
-
cluster.on("disconnect", (worker) => {
|
|
164
|
-
const appWorker = new AppProcessWorker(worker);
|
|
165
|
-
this.log("[master] app_worker#%s:%s disconnect, suicide: %s, state: %s, current workers: %j", appWorker.id, appWorker.workerId, appWorker.exitedAfterDisconnect, appWorker.state, Object.keys(cluster.workers));
|
|
166
|
-
});
|
|
167
|
-
cluster.on("exit", (worker, code, signal) => {
|
|
168
|
-
const appWorker = new AppProcessWorker(worker);
|
|
169
|
-
this.messenger.send({
|
|
170
|
-
action: "app-exit",
|
|
171
|
-
data: {
|
|
172
|
-
workerId: appWorker.workerId,
|
|
173
|
-
code,
|
|
174
|
-
signal
|
|
175
|
-
},
|
|
176
|
-
to: "master",
|
|
177
|
-
from: "app"
|
|
178
|
-
});
|
|
179
|
-
});
|
|
180
|
-
return this;
|
|
181
|
-
}
|
|
182
|
-
async kill(timeout) {
|
|
183
|
-
await Promise.all(Object.keys(cluster.workers).map((id) => {
|
|
184
|
-
const worker = cluster.workers[id];
|
|
185
|
-
Reflect.set(worker, "disableRefork", true);
|
|
186
|
-
return terminate(worker.process, timeout);
|
|
187
|
-
}));
|
|
188
|
-
}
|
|
189
|
-
};
|
|
190
|
-
|
|
191
|
-
//#endregion
|
|
192
|
-
//#region src/utils/mode/impl/worker_threads/app.ts
|
|
193
|
-
var AppThreadWorker = class extends BaseAppWorker {
|
|
194
|
-
#state = "none";
|
|
195
|
-
#id;
|
|
196
|
-
constructor(instance, id) {
|
|
197
|
-
super(instance);
|
|
198
|
-
this.#id = id;
|
|
199
|
-
}
|
|
200
|
-
get id() {
|
|
201
|
-
return this.#id;
|
|
202
|
-
}
|
|
203
|
-
get workerId() {
|
|
204
|
-
return this.instance.threadId;
|
|
205
|
-
}
|
|
206
|
-
get state() {
|
|
207
|
-
return this.#state;
|
|
208
|
-
}
|
|
209
|
-
set state(val) {
|
|
210
|
-
this.#state = val;
|
|
211
|
-
}
|
|
212
|
-
get exitedAfterDisconnect() {
|
|
213
|
-
return true;
|
|
214
|
-
}
|
|
215
|
-
get exitCode() {
|
|
216
|
-
return 0;
|
|
217
|
-
}
|
|
218
|
-
send(message) {
|
|
219
|
-
this.instance.postMessage(message);
|
|
220
|
-
}
|
|
221
|
-
clean() {
|
|
222
|
-
this.instance.removeAllListeners();
|
|
223
|
-
}
|
|
224
|
-
static get workerId() {
|
|
225
|
-
return threadId;
|
|
226
|
-
}
|
|
227
|
-
static on(event, listener) {
|
|
228
|
-
parentPort.on(event, listener);
|
|
229
|
-
}
|
|
230
|
-
static send(message) {
|
|
231
|
-
message.senderWorkerId = String(threadId);
|
|
232
|
-
parentPort.postMessage(message);
|
|
233
|
-
}
|
|
234
|
-
static kill() {
|
|
235
|
-
process.exit(1);
|
|
236
|
-
}
|
|
237
|
-
static gracefulExit(options) {
|
|
238
|
-
process.on("exit", async (code) => {
|
|
239
|
-
if (typeof options.beforeExit === "function") await options.beforeExit();
|
|
240
|
-
process.exit(code);
|
|
241
|
-
});
|
|
242
|
-
}
|
|
243
|
-
};
|
|
244
|
-
var AppThreadUtils = class extends BaseAppUtils {
|
|
245
|
-
#workers = [];
|
|
246
|
-
#forkSingle(appPath, options, id) {
|
|
247
|
-
const worker = new Worker(appPath, options);
|
|
248
|
-
this.#workers.push(worker);
|
|
249
|
-
const appWorker = new AppThreadWorker(worker, id);
|
|
250
|
-
this.emit("worker_forked", appWorker);
|
|
251
|
-
appWorker.disableRefork = true;
|
|
252
|
-
worker.on("message", (msg) => {
|
|
253
|
-
if (typeof msg === "string") msg = {
|
|
254
|
-
action: msg,
|
|
255
|
-
data: msg
|
|
256
|
-
};
|
|
257
|
-
msg.from = "app";
|
|
258
|
-
this.messenger.send(msg);
|
|
259
|
-
});
|
|
260
|
-
this.log("[master] app_worker#%s (tid:%s) start", appWorker.id, appWorker.workerId);
|
|
261
|
-
let debugPort = process.debugPort;
|
|
262
|
-
if (this.options.isDebug) {
|
|
263
|
-
debugPort++;
|
|
264
|
-
this.messenger.send({
|
|
265
|
-
to: "parent",
|
|
266
|
-
from: "app",
|
|
267
|
-
action: "debug",
|
|
268
|
-
data: {
|
|
269
|
-
debugPort,
|
|
270
|
-
pid: appWorker.workerId,
|
|
271
|
-
workerId: appWorker.workerId
|
|
272
|
-
}
|
|
273
|
-
});
|
|
274
|
-
}
|
|
275
|
-
worker.on("exit", async (code) => {
|
|
276
|
-
appWorker.state = "dead";
|
|
277
|
-
this.messenger.send({
|
|
278
|
-
action: "app-exit",
|
|
279
|
-
data: {
|
|
280
|
-
workerId: appWorker.workerId,
|
|
281
|
-
code
|
|
282
|
-
},
|
|
283
|
-
to: "master",
|
|
284
|
-
from: "app"
|
|
285
|
-
});
|
|
286
|
-
await setTimeout(1e3);
|
|
287
|
-
this.#forkSingle(appPath, options, id);
|
|
288
|
-
});
|
|
289
|
-
}
|
|
290
|
-
fork() {
|
|
291
|
-
this.startTime = Date.now();
|
|
292
|
-
this.startSuccessCount = 0;
|
|
293
|
-
const ports = this.options.ports ?? [];
|
|
294
|
-
if (!ports.length) ports.push(this.options.port);
|
|
295
|
-
this.options.workers = ports.length;
|
|
296
|
-
let i = 0;
|
|
297
|
-
do {
|
|
298
|
-
const options = Object.assign({}, this.options, { port: ports[i] });
|
|
299
|
-
const argv = [JSON.stringify(options)];
|
|
300
|
-
this.#forkSingle(this.getAppWorkerFile(), { argv }, ++i);
|
|
301
|
-
} while (i < ports.length);
|
|
302
|
-
return this;
|
|
303
|
-
}
|
|
304
|
-
async kill() {
|
|
305
|
-
for (const worker of this.#workers) {
|
|
306
|
-
const id = Reflect.get(worker, "id");
|
|
307
|
-
this.log(`[master] kill app worker#${id} (worker_threads) by worker.terminate()`);
|
|
308
|
-
worker.removeAllListeners();
|
|
309
|
-
worker.terminate();
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
};
|
|
313
|
-
|
|
314
|
-
//#endregion
|
|
315
|
-
export { AppProcessUtils, AppProcessWorker, AppThreadUtils, AppThreadWorker };
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { debuglog } from "node:util";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { once } from "node:events";
|
|
4
|
-
import { fileURLToPath } from "node:url";
|
|
5
|
-
import { ChildProcess } from "node:child_process";
|
|
6
|
-
import { setTimeout } from "node:timers/promises";
|
|
7
|
-
import { pstree } from "@fengmk2/ps-tree";
|
|
8
|
-
|
|
9
|
-
//#region src/dirname.ts
|
|
10
|
-
function getSrcDirname() {
|
|
11
|
-
if (typeof __dirname !== "undefined") return __dirname;
|
|
12
|
-
return path.dirname(fileURLToPath(import.meta.url));
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
//#endregion
|
|
16
|
-
//#region src/utils/terminate.ts
|
|
17
|
-
const debug = debuglog("egg/cluster/utils/terminate");
|
|
18
|
-
async function terminate(subProcess, timeout) {
|
|
19
|
-
const pid = subProcess.process?.pid ?? subProcess.pid;
|
|
20
|
-
const childPids = await getChildPids(pid);
|
|
21
|
-
await Promise.all([killProcess(subProcess, timeout), killChildren(childPids, timeout)]);
|
|
22
|
-
}
|
|
23
|
-
async function killProcess(subProcess, timeout) {
|
|
24
|
-
(subProcess.process ?? subProcess).kill("SIGTERM");
|
|
25
|
-
await Promise.race([once(subProcess, "exit"), setTimeout(timeout)]);
|
|
26
|
-
if (subProcess.killed) return;
|
|
27
|
-
(subProcess.process ?? subProcess).kill("SIGKILL");
|
|
28
|
-
}
|
|
29
|
-
async function killChildren(childrenPids, timeout) {
|
|
30
|
-
if (childrenPids.length === 0) return;
|
|
31
|
-
kill(childrenPids, "SIGTERM");
|
|
32
|
-
const start = Date.now();
|
|
33
|
-
const checkInterval = 400;
|
|
34
|
-
let unterminated = [];
|
|
35
|
-
while (Date.now() - start < timeout - checkInterval) {
|
|
36
|
-
await setTimeout(checkInterval);
|
|
37
|
-
unterminated = getUnterminatedProcesses(childrenPids);
|
|
38
|
-
if (unterminated.length === 0) return;
|
|
39
|
-
}
|
|
40
|
-
kill(unterminated, "SIGKILL");
|
|
41
|
-
}
|
|
42
|
-
async function getChildPids(pid) {
|
|
43
|
-
let childrenPids = [];
|
|
44
|
-
try {
|
|
45
|
-
childrenPids = (await pstree(pid)).map((c) => parseInt(c.PID));
|
|
46
|
-
} catch (err) {
|
|
47
|
-
debug("pstree %s error: %s, ignore it", pid, err);
|
|
48
|
-
}
|
|
49
|
-
return childrenPids;
|
|
50
|
-
}
|
|
51
|
-
function kill(pids, signal) {
|
|
52
|
-
for (const pid of pids) try {
|
|
53
|
-
process.kill(pid, signal);
|
|
54
|
-
} catch (err) {
|
|
55
|
-
debug("kill %s error: %s, signal: %s, ignore it", pid, err, signal);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
function getUnterminatedProcesses(pids) {
|
|
59
|
-
return pids.filter((pid) => {
|
|
60
|
-
try {
|
|
61
|
-
process.kill(pid, 0);
|
|
62
|
-
return true;
|
|
63
|
-
} catch (err) {
|
|
64
|
-
debug("kill %s error: %s, it still alive", pid, err);
|
|
65
|
-
return false;
|
|
66
|
-
}
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
//#endregion
|
|
71
|
-
export { getSrcDirname, terminate };
|