@eggjs/cluster 4.0.0-beta.19 → 4.0.0-beta.20

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.
Files changed (33) hide show
  1. package/dist/agent-griHEaCW.js +246 -0
  2. package/dist/agent_worker.js +2 -2
  3. package/dist/app-5Was1vub.js +315 -0
  4. package/dist/app_worker.js +2 -2
  5. package/dist/index.d.ts +440 -5
  6. package/dist/index.js +692 -4
  7. package/dist/{utils/terminate.js → terminate-w3g0oQgq.js} +10 -1
  8. package/package.json +5 -5
  9. package/dist/dirname.js +0 -11
  10. package/dist/error/ClusterAgentWorkerError.d.ts +0 -13
  11. package/dist/error/ClusterAgentWorkerError.js +0 -22
  12. package/dist/error/ClusterWorkerExceptionError.d.ts +0 -10
  13. package/dist/error/ClusterWorkerExceptionError.js +0 -17
  14. package/dist/master.d.ts +0 -96
  15. package/dist/master.js +0 -426
  16. package/dist/utils/messenger.d.ts +0 -96
  17. package/dist/utils/messenger.js +0 -144
  18. package/dist/utils/mode/base/agent.d.ts +0 -45
  19. package/dist/utils/mode/base/agent.js +0 -63
  20. package/dist/utils/mode/base/app.d.ts +0 -56
  21. package/dist/utils/mode/base/app.js +0 -77
  22. package/dist/utils/mode/impl/process/agent.d.ts +0 -22
  23. package/dist/utils/mode/impl/process/agent.js +0 -93
  24. package/dist/utils/mode/impl/process/app.d.ts +0 -12
  25. package/dist/utils/mode/impl/process/app.js +0 -117
  26. package/dist/utils/mode/impl/worker_threads/agent.d.ts +0 -22
  27. package/dist/utils/mode/impl/worker_threads/agent.js +0 -79
  28. package/dist/utils/mode/impl/worker_threads/app.d.ts +0 -13
  29. package/dist/utils/mode/impl/worker_threads/app.js +0 -128
  30. package/dist/utils/options.d.ts +0 -83
  31. package/dist/utils/options.js +0 -56
  32. package/dist/utils/worker_manager.d.ts +0 -32
  33. package/dist/utils/worker_manager.js +0 -68
@@ -1,9 +1,18 @@
1
1
  import { debuglog } from "node:util";
2
+ import path from "node:path";
2
3
  import { once } from "node:events";
4
+ import { fileURLToPath } from "node:url";
3
5
  import { ChildProcess } from "node:child_process";
4
6
  import { setTimeout } from "node:timers/promises";
5
7
  import { pstree } from "@fengmk2/ps-tree";
6
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
7
16
  //#region src/utils/terminate.ts
8
17
  const debug = debuglog("egg/cluster/utils/terminate");
9
18
  async function terminate(subProcess, timeout) {
@@ -59,4 +68,4 @@ function getUnterminatedProcesses(pids) {
59
68
  }
60
69
 
61
70
  //#endregion
62
- export { terminate };
71
+ export { getSrcDirname, terminate };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eggjs/cluster",
3
- "version": "4.0.0-beta.19",
3
+ "version": "4.0.0-beta.20",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -45,7 +45,7 @@
45
45
  "sendmessage": "^3.0.1",
46
46
  "terminal-link": "^5.0.0",
47
47
  "utility": "^2.5.0",
48
- "@eggjs/utils": "5.0.0-beta.19"
48
+ "@eggjs/utils": "5.0.0-beta.20"
49
49
  },
50
50
  "devDependencies": {
51
51
  "address": "2",
@@ -55,9 +55,9 @@
55
55
  "typescript": "^5.9.3",
56
56
  "urllib": "^4.8.2",
57
57
  "vitest": "4.0.0-beta.16",
58
- "@eggjs/supertest": "9.0.0-beta.19",
59
- "@eggjs/tsconfig": "3.1.0-beta.19",
60
- "@eggjs/mock": "7.0.0-beta.19"
58
+ "@eggjs/supertest": "9.0.0-beta.20",
59
+ "@eggjs/mock": "7.0.0-beta.20",
60
+ "@eggjs/tsconfig": "3.1.0-beta.20"
61
61
  },
62
62
  "engines": {
63
63
  "node": ">=22.18.0"
package/dist/dirname.js DELETED
@@ -1,11 +0,0 @@
1
- import path from "node:path";
2
- import { fileURLToPath } from "node:url";
3
-
4
- //#region src/dirname.ts
5
- function getSrcDirname() {
6
- if (typeof __dirname !== "undefined") return __dirname;
7
- return path.dirname(fileURLToPath(import.meta.url));
8
- }
9
-
10
- //#endregion
11
- export { getSrcDirname };
@@ -1,13 +0,0 @@
1
- //#region src/error/ClusterAgentWorkerError.d.ts
2
- declare class ClusterAgentWorkerError extends Error {
3
- id: number;
4
- /**
5
- * pid in process mode
6
- * tid in worker_threads mode
7
- */
8
- workerId: number;
9
- status: string;
10
- constructor(id: number, workerId: number, status: string, error: Error);
11
- }
12
- //#endregion
13
- export { ClusterAgentWorkerError };
@@ -1,22 +0,0 @@
1
- //#region src/error/ClusterAgentWorkerError.ts
2
- var ClusterAgentWorkerError = class extends Error {
3
- id;
4
- /**
5
- * pid in process mode
6
- * tid in worker_threads mode
7
- */
8
- workerId;
9
- status;
10
- constructor(id, workerId, status, error) {
11
- const message = `Got agent worker error: ${error.message}`;
12
- super(message, { cause: error });
13
- this.name = this.constructor.name;
14
- this.id = id;
15
- this.workerId = workerId;
16
- this.status = status;
17
- Error.captureStackTrace(this, this.constructor);
18
- }
19
- };
20
-
21
- //#endregion
22
- export { ClusterAgentWorkerError };
@@ -1,10 +0,0 @@
1
- //#region src/error/ClusterWorkerExceptionError.d.ts
2
- declare class ClusterWorkerExceptionError extends Error {
3
- count: {
4
- agent: number;
5
- worker: number;
6
- };
7
- constructor(agent: number, worker: number);
8
- }
9
- //#endregion
10
- export { ClusterWorkerExceptionError };
@@ -1,17 +0,0 @@
1
- //#region src/error/ClusterWorkerExceptionError.ts
2
- var ClusterWorkerExceptionError = class extends Error {
3
- count;
4
- constructor(agent, worker) {
5
- const message = `[master] ${agent} agent and ${worker} worker(s) alive, exit to avoid unknown state`;
6
- super(message);
7
- this.name = this.constructor.name;
8
- this.count = {
9
- agent,
10
- worker
11
- };
12
- Error.captureStackTrace(this, this.constructor);
13
- }
14
- };
15
-
16
- //#endregion
17
- export { ClusterWorkerExceptionError };
package/dist/master.d.ts DELETED
@@ -1,96 +0,0 @@
1
- import { WorkerManager } from "./utils/worker_manager.js";
2
- import { Messenger } from "./utils/messenger.js";
3
- import { BaseAppWorker } from "./utils/mode/base/app.js";
4
- import { ClusterOptions, ParsedClusterOptions } from "./utils/options.js";
5
- import { AgentProcessUtils } from "./utils/mode/impl/process/agent.js";
6
- import { AppProcessUtils } from "./utils/mode/impl/process/app.js";
7
- import { AgentThreadUtils } from "./utils/mode/impl/worker_threads/agent.js";
8
- import { AppThreadUtils } from "./utils/mode/impl/worker_threads/app.js";
9
- import { ReadyEventEmitter } from "get-ready";
10
- import { EggConsoleLogger } from "egg-logger";
11
- import * as worker_threads0 from "worker_threads";
12
- import * as cluster0 from "cluster";
13
-
14
- //#region src/master.d.ts
15
- interface MasterOptions extends ParsedClusterOptions {
16
- clusterPort?: number;
17
- stickyWorkerPort?: number;
18
- }
19
- declare class Master extends ReadyEventEmitter {
20
- #private;
21
- options: MasterOptions;
22
- isStarted: boolean;
23
- workerManager: WorkerManager;
24
- messenger: Messenger;
25
- isProduction: boolean;
26
- agentWorkerIndex: number;
27
- closed: boolean;
28
- logger: EggConsoleLogger;
29
- agentWorker: AgentProcessUtils | AgentThreadUtils;
30
- appWorker: AppProcessUtils | AppThreadUtils;
31
- constructor(options?: ClusterOptions);
32
- startByProcess(): void;
33
- startByWorkerThreads(): void;
34
- detectPorts(): Promise<void>;
35
- log(msg: string, ...args: any[]): void;
36
- startMasterSocketServer(cb: (err?: Error) => void): void;
37
- stickyWorker(ip: string): BaseAppWorker<worker_threads0.Worker | cluster0.Worker>;
38
- forkAgentWorker(): void;
39
- forkAppWorkers(): void;
40
- /**
41
- * close agent worker, App Worker will closed by cluster
42
- *
43
- * https://www.exratione.com/2013/05/die-child-process-die/
44
- * make sure Agent Worker exit before master exit
45
- *
46
- * @param {number} timeout - kill agent timeout
47
- * @return {Promise} -
48
- */
49
- killAgentWorker(timeout: number): Promise<void>;
50
- killAppWorkers(timeout: number): Promise<void>;
51
- /**
52
- * Agent Worker exit handler
53
- * Will exit during startup, and refork during running.
54
- */
55
- onAgentExit(data: {
56
- /** exit code */
57
- code: number;
58
- /** received signal */
59
- signal: string;
60
- }): void;
61
- onAgentStart(): void;
62
- /**
63
- * App Worker exit handler
64
- */
65
- onAppExit(data: {
66
- workerId: number;
67
- code: number;
68
- signal: string;
69
- }): void;
70
- /**
71
- * after app worker
72
- */
73
- onAppStart(data: {
74
- workerId: number;
75
- address: ListeningAddress;
76
- }): void;
77
- /**
78
- * master exit handler
79
- */
80
- onExit(code: number): void;
81
- onSignal(signal: string): void;
82
- /**
83
- * reload workers, for develop purpose
84
- */
85
- onReload(): void;
86
- close(): Promise<void>;
87
- _doClose(): Promise<void>;
88
- }
89
- interface ListeningAddress {
90
- port: number;
91
- protocol: string;
92
- address?: string;
93
- addressType?: number;
94
- }
95
- //#endregion
96
- export { Master, MasterOptions };
package/dist/master.js DELETED
@@ -1,426 +0,0 @@
1
- import { parseOptions } from "./utils/options.js";
2
- import { WorkerManager } from "./utils/worker_manager.js";
3
- import { Messenger } from "./utils/messenger.js";
4
- import { AgentProcessUtils } from "./utils/mode/impl/process/agent.js";
5
- import { AppProcessUtils } from "./utils/mode/impl/process/app.js";
6
- import { AgentThreadUtils } from "./utils/mode/impl/worker_threads/agent.js";
7
- import { AppThreadUtils } from "./utils/mode/impl/worker_threads/app.js";
8
- import { ClusterWorkerExceptionError } from "./error/ClusterWorkerExceptionError.js";
9
- import os from "node:os";
10
- import v8 from "node:v8";
11
- import util, { debuglog } from "node:util";
12
- import path from "node:path";
13
- import fs from "node:fs";
14
- import net from "node:net";
15
- import { ReadyEventEmitter } from "get-ready";
16
- import { detectPort } from "detect-port";
17
- import { reload } from "cluster-reload";
18
- import { EggConsoleLogger } from "egg-logger";
19
- import { readJSONSync } from "utility";
20
- import terminalLink from "terminal-link";
21
-
22
- //#region src/master.ts
23
- const debug = debuglog("egg/cluster/master");
24
- var Master = class extends ReadyEventEmitter {
25
- options;
26
- isStarted = false;
27
- workerManager;
28
- messenger;
29
- isProduction;
30
- agentWorkerIndex = 0;
31
- closed = false;
32
- logger;
33
- agentWorker;
34
- appWorker;
35
- #logMethod;
36
- #realPort;
37
- #protocol;
38
- #appAddress;
39
- constructor(options) {
40
- super();
41
- this.#start(options).catch((err) => {
42
- this.ready(err);
43
- });
44
- }
45
- async #start(options) {
46
- this.options = await parseOptions(options);
47
- this.workerManager = new WorkerManager();
48
- this.messenger = new Messenger(this, this.workerManager);
49
- this.isProduction = isProduction(this.options);
50
- this.#realPort = this.options.port;
51
- this.#protocol = this.options.https ? "https" : "http";
52
- this.isStarted = false;
53
- this.logger = new EggConsoleLogger({ level: process.env.EGG_MASTER_LOGGER_LEVEL ?? "INFO" });
54
- this.#logMethod = "info";
55
- if (this.options.env === "local" || process.env.NODE_ENV === "development") this.#logMethod = "debug";
56
- const frameworkPath = this.options.framework;
57
- const frameworkPkg = readJSONSync(path.join(frameworkPath, "package.json"));
58
- if (this.options.startMode === "worker_threads") this.startByWorkerThreads();
59
- else this.startByProcess();
60
- this.log(`[master] =================== ${frameworkPkg.name} start 🥚🥚🥚🥚 =====================`);
61
- this.logger.info(`[master] node version ${process.version}`);
62
- /* istanbul ignore next */
63
- if ("alinode" in process) this.logger.info(`[master] alinode version ${process.alinode}`);
64
- this.logger.info(`[master] ${frameworkPkg.name} version ${frameworkPkg.version}`);
65
- if (this.isProduction) this.logger.info("[master] start with options:%s%s", os.EOL, JSON.stringify(this.options, null, 2));
66
- else this.log("[master] start with options: %j", this.options);
67
- this.log("[master] start with env: isProduction: %s, EGG_SERVER_ENV: %s, NODE_ENV: %s", this.isProduction, this.options.env, process.env.NODE_ENV);
68
- const startTime = Date.now();
69
- this.ready(() => {
70
- this.isStarted = true;
71
- const stickyMsg = this.options.sticky ? " with STICKY MODE!" : "";
72
- const startedURL = terminalLink(this.#appAddress, this.#appAddress, { fallback: false });
73
- this.logger.info("[master] %s started on %s (%sms)%s", frameworkPkg.name, startedURL, Date.now() - startTime, stickyMsg);
74
- if (this.options.debugPort) {
75
- const url = getAddress({
76
- port: this.options.debugPort,
77
- protocol: "http"
78
- });
79
- const debugPortURL = terminalLink(url, url, { fallback: false });
80
- this.logger.info("[master] %s started debug port on %s", frameworkPkg.name, debugPortURL);
81
- }
82
- const action = "egg-ready";
83
- this.messenger.send({
84
- action,
85
- to: "parent",
86
- data: {
87
- port: this.#realPort,
88
- debugPort: this.options.debugPort,
89
- address: this.#appAddress,
90
- protocol: this.#protocol
91
- }
92
- });
93
- this.messenger.send({
94
- action,
95
- to: "app",
96
- data: this.options
97
- });
98
- this.messenger.send({
99
- action,
100
- to: "agent",
101
- data: this.options
102
- });
103
- if (this.isProduction) this.workerManager.startCheck();
104
- });
105
- this.on("agent-exit", this.onAgentExit.bind(this));
106
- this.on("agent-start", this.onAgentStart.bind(this));
107
- this.on("app-exit", this.onAppExit.bind(this));
108
- this.on("app-start", this.onAppStart.bind(this));
109
- this.on("reload-worker", this.onReload.bind(this));
110
- this.once("agent-start", this.forkAppWorkers.bind(this));
111
- this.on("realport", ({ port, protocol }) => {
112
- if (port) this.#realPort = port;
113
- if (protocol) this.#protocol = protocol;
114
- });
115
- process.once("SIGINT", this.onSignal.bind(this, "SIGINT"));
116
- process.once("SIGQUIT", this.onSignal.bind(this, "SIGQUIT"));
117
- process.once("SIGTERM", this.onSignal.bind(this, "SIGTERM"));
118
- process.once("exit", this.onExit.bind(this));
119
- if (this.options.pidFile) {
120
- fs.mkdirSync(path.dirname(this.options.pidFile), { recursive: true });
121
- fs.writeFileSync(this.options.pidFile, process.pid.toString(), "utf-8");
122
- }
123
- this.detectPorts().then(() => {
124
- this.forkAgentWorker();
125
- });
126
- this.workerManager.on("exception", (count) => {
127
- const err = new ClusterWorkerExceptionError(count.agent, count.worker);
128
- this.logger.error(err);
129
- process.exit(1);
130
- });
131
- }
132
- startByProcess() {
133
- this.agentWorker = new AgentProcessUtils(this.options, {
134
- log: this.log.bind(this),
135
- logger: this.logger,
136
- messenger: this.messenger
137
- });
138
- this.appWorker = new AppProcessUtils(this.options, {
139
- log: this.log.bind(this),
140
- logger: this.logger,
141
- messenger: this.messenger,
142
- isProduction: this.isProduction
143
- });
144
- }
145
- startByWorkerThreads() {
146
- this.agentWorker = new AgentThreadUtils(this.options, {
147
- log: this.log.bind(this),
148
- logger: this.logger,
149
- messenger: this.messenger
150
- });
151
- this.appWorker = new AppThreadUtils(this.options, {
152
- log: this.log.bind(this),
153
- logger: this.logger,
154
- messenger: this.messenger,
155
- isProduction: this.isProduction
156
- });
157
- }
158
- async detectPorts() {
159
- try {
160
- const clusterPort = await detectPort();
161
- this.options.clusterPort = clusterPort;
162
- if (this.options.sticky) {
163
- const stickyWorkerPort = await detectPort();
164
- this.options.stickyWorkerPort = stickyWorkerPort;
165
- }
166
- } catch (err) {
167
- this.logger.error(err);
168
- process.exit(1);
169
- }
170
- }
171
- log(msg, ...args) {
172
- this.logger[this.#logMethod](msg, ...args);
173
- }
174
- startMasterSocketServer(cb) {
175
- net.createServer({ pauseOnConnect: true }, (connection) => {
176
- /* istanbul ignore next */
177
- if (!connection.remoteAddress) connection.destroy();
178
- else this.stickyWorker(connection.remoteAddress).instance.send("sticky-session:connection", connection);
179
- }).listen(this.#realPort, cb);
180
- }
181
- stickyWorker(ip) {
182
- const workerNumbers = this.options.workers;
183
- const ws = this.workerManager.listWorkerIds();
184
- let s = "";
185
- for (let i = 0; i < ip.length; i++) if (!isNaN(parseInt(ip[i]))) s += ip[i];
186
- const pid = ws[Number(s) % workerNumbers];
187
- return this.workerManager.getWorker(pid);
188
- }
189
- forkAgentWorker() {
190
- this.agentWorker.on("agent_forked", (agent) => {
191
- this.workerManager.setAgent(agent);
192
- });
193
- this.agentWorker.fork();
194
- }
195
- forkAppWorkers() {
196
- this.appWorker.on("worker_forked", (worker) => {
197
- this.workerManager.setWorker(worker);
198
- });
199
- this.appWorker.fork();
200
- }
201
- /**
202
- * close agent worker, App Worker will closed by cluster
203
- *
204
- * https://www.exratione.com/2013/05/die-child-process-die/
205
- * make sure Agent Worker exit before master exit
206
- *
207
- * @param {number} timeout - kill agent timeout
208
- * @return {Promise} -
209
- */
210
- async killAgentWorker(timeout) {
211
- await this.agentWorker.kill(timeout);
212
- }
213
- async killAppWorkers(timeout) {
214
- await this.appWorker.kill(timeout);
215
- }
216
- /**
217
- * Agent Worker exit handler
218
- * Will exit during startup, and refork during running.
219
- */
220
- onAgentExit(data) {
221
- if (this.closed) return;
222
- this.messenger.send({
223
- action: "egg-pids",
224
- to: "app",
225
- data: []
226
- });
227
- const agentWorker = this.agentWorker;
228
- this.workerManager.deleteAgent();
229
- const err = new Error(util.format("[master] agent_worker#%s:%s died (code: %s, signal: %s)", agentWorker.instance.id, agentWorker.instance.workerId, data.code, data.signal));
230
- err.name = "AgentWorkerDiedError";
231
- this.logger.error(err);
232
- agentWorker.clean();
233
- if (this.isStarted) {
234
- this.log("[master] try to start a new agent_worker after 1s ...");
235
- setTimeout(() => {
236
- this.logger.info("[master] new agent_worker starting...");
237
- this.forkAgentWorker();
238
- }, 1e3);
239
- this.messenger.send({
240
- action: "agent-worker-died",
241
- to: "parent"
242
- });
243
- } else {
244
- this.logger.error("[master] agent_worker#%s:%s start fail, exiting with code:1", agentWorker.instance.id, agentWorker.instance.workerId);
245
- process.exit(1);
246
- }
247
- }
248
- onAgentStart() {
249
- this.agentWorker.instance.status = "started";
250
- if (this.appWorker.isAllWorkerStarted) this.messenger.send({
251
- action: "egg-ready",
252
- to: "agent",
253
- data: this.options
254
- });
255
- this.messenger.send({
256
- action: "egg-pids",
257
- to: "app",
258
- data: [this.agentWorker.instance.workerId]
259
- });
260
- if (this.isStarted) this.messenger.send({
261
- action: "egg-pids",
262
- to: "agent",
263
- data: this.workerManager.getListeningWorkerIds()
264
- });
265
- this.messenger.send({
266
- action: "agent-start",
267
- to: "app"
268
- });
269
- this.logger.info("[master] agent_worker#%s:%s started (%sms)", this.agentWorker.instance.id, this.agentWorker.instance.workerId, Date.now() - this.agentWorker.startTime);
270
- }
271
- /**
272
- * App Worker exit handler
273
- */
274
- onAppExit(data) {
275
- if (this.closed) return;
276
- const worker = this.workerManager.getWorker(data.workerId);
277
- if (!worker.isDevReload) {
278
- const signal = data.signal;
279
- const message = util.format("[master] app_worker#%s:%s died (code: %s, signal: %s, suicide: %s, state: %s), current workers: %j", worker.id, worker.workerId, worker.exitCode, signal, worker.exitedAfterDisconnect, worker.state, this.workerManager.listWorkerIds());
280
- if (this.options.isDebug && signal === "SIGKILL") {
281
- this.logger.error(message);
282
- this.logger.error("[master] worker kill by debugger, exiting...");
283
- setTimeout(() => this.close(), 10);
284
- } else {
285
- const err = new Error(message);
286
- err.name = "AppWorkerDiedError";
287
- this.logger.error(err);
288
- }
289
- }
290
- worker.clean();
291
- this.workerManager.deleteWorker(data.workerId);
292
- this.messenger.send({
293
- action: "egg-pids",
294
- to: "agent",
295
- data: this.workerManager.getListeningWorkerIds()
296
- });
297
- if (this.appWorker.isAllWorkerStarted) this.messenger.send({
298
- action: "app-worker-died",
299
- to: "parent"
300
- });
301
- else {
302
- this.logger.error("[master] app_worker#%s:%s start fail, exiting with code:1", worker.id, worker.workerId);
303
- process.exit(1);
304
- }
305
- }
306
- /**
307
- * after app worker
308
- */
309
- onAppStart(data) {
310
- const worker = this.workerManager.getWorker(data.workerId);
311
- debug("got app_worker#%s:%s app-start event, data: %j", worker.id, worker.workerId, data);
312
- const address = data.address;
313
- if (this.options.sticky) {
314
- if (String(address.port) !== String(this.options.stickyWorkerPort)) return;
315
- } else if (this.options.startMode !== "worker_threads" && !isUnixSock(address) && String(address.port) !== String(this.#realPort)) return;
316
- worker.state = "listening";
317
- this.messenger.send({
318
- action: "egg-pids",
319
- to: "agent",
320
- data: this.workerManager.getListeningWorkerIds()
321
- });
322
- this.messenger.send({
323
- action: "egg-pids",
324
- to: "app",
325
- data: [this.agentWorker.instance.workerId],
326
- receiverWorkerId: String(worker.workerId),
327
- receiverPid: String(worker.workerId)
328
- });
329
- this.appWorker.startSuccessCount++;
330
- const remain = this.appWorker.isAllWorkerStarted ? 0 : this.options.workers - this.appWorker.startSuccessCount;
331
- this.log("[master] app_worker#%s:%s started at %s, remain %s (%sms)", worker.id, worker.workerId, address.port, remain, Date.now() - this.appWorker.startTime);
332
- if (this.appWorker.isAllWorkerStarted) this.messenger.send({
333
- action: "egg-ready",
334
- to: "app",
335
- data: this.options
336
- });
337
- if (this.appWorker.isAllWorkerStarted) worker.disableRefork = false;
338
- if (this.appWorker.isAllWorkerStarted || this.appWorker.startSuccessCount < this.options.workers) return;
339
- this.appWorker.isAllWorkerStarted = true;
340
- for (const worker$1 of this.workerManager.listWorkers()) worker$1.disableRefork = false;
341
- address.protocol = this.#protocol;
342
- address.port = this.options.sticky ? this.#realPort : address.port;
343
- this.#appAddress = getAddress(address);
344
- if (this.options.sticky) this.startMasterSocketServer((err) => {
345
- if (err) return this.ready(err);
346
- this.ready(true);
347
- });
348
- else this.ready(true);
349
- }
350
- /**
351
- * master exit handler
352
- */
353
- onExit(code) {
354
- if (this.options.pidFile && fs.existsSync(this.options.pidFile)) try {
355
- fs.unlinkSync(this.options.pidFile);
356
- } catch (err) {
357
- /* istanbul ignore next */
358
- this.logger.error("[master] delete pidFile %s fail with %s", this.options.pidFile, err.message);
359
- }
360
- const level = code === 0 ? "info" : "error";
361
- this.logger[level]("[master] exit with code:%s", code);
362
- }
363
- onSignal(signal) {
364
- if (this.closed) return;
365
- this.logger.info("[master] master is killed by signal %s, closing", signal);
366
- const { used_heap_size, heap_size_limit } = v8.getHeapStatistics();
367
- this.logger.info("[master] system memory: total %s, free %s", os.totalmem(), os.freemem());
368
- this.logger.info("[master] process info: heap_limit %s, heap_used %s", heap_size_limit, used_heap_size);
369
- this.close();
370
- }
371
- /**
372
- * reload workers, for develop purpose
373
- */
374
- onReload() {
375
- this.log("[master] reload %s workers...", this.options.workers);
376
- for (const worker of this.workerManager.listWorkers()) worker.isDevReload = true;
377
- reload(this.options.workers);
378
- }
379
- async close() {
380
- this.closed = true;
381
- try {
382
- await this._doClose();
383
- this.log("[master] close done, exiting with code:0");
384
- process.exit(0);
385
- } catch (e) {
386
- this.logger.error("[master] close with error: ", e);
387
- process.exit(1);
388
- }
389
- }
390
- async _doClose() {
391
- const legacyTimeout = process.env.EGG_MASTER_CLOSE_TIMEOUT || "5000";
392
- const appTimeout = parseInt(process.env.EGG_APP_CLOSE_TIMEOUT || legacyTimeout);
393
- const agentTimeout = parseInt(process.env.EGG_AGENT_CLOSE_TIMEOUT || legacyTimeout);
394
- this.logger.info("[master] send kill SIGTERM to app workers, will exit with code:0 after %sms", appTimeout);
395
- this.logger.info("[master] wait %sms", appTimeout);
396
- try {
397
- await this.killAppWorkers(appTimeout);
398
- } catch (e) {
399
- this.logger.error("[master] app workers exit error: ", e);
400
- }
401
- this.logger.info("[master] send kill SIGTERM to agent worker, will exit with code:0 after %sms", agentTimeout);
402
- this.logger.info("[master] wait %sms", agentTimeout);
403
- try {
404
- await this.killAgentWorker(agentTimeout);
405
- } catch (e) {
406
- this.logger.error("[master] agent worker exit error: ", e);
407
- }
408
- }
409
- };
410
- function isProduction(options) {
411
- if (options.env) return options.env !== "local" && options.env !== "unittest";
412
- return process.env.NODE_ENV === "production";
413
- }
414
- function getAddress({ addressType, address, port, protocol }) {
415
- if (addressType === -1) return address;
416
- if (address === "::") address = "";
417
- if (!address && process.env.HOST && process.env.HOST !== "0.0.0.0") address = process.env.HOST;
418
- if (!address) address = "127.0.0.1";
419
- return `${protocol}://${address}:${port}`;
420
- }
421
- function isUnixSock(address) {
422
- return address.addressType === -1;
423
- }
424
-
425
- //#endregion
426
- export { Master };