@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,117 +0,0 @@
1
- import { BaseAppUtils, BaseAppWorker } from "../../base/app.js";
2
- import { terminate } from "../../../terminate.js";
3
- import { sendmessage } from "sendmessage";
4
- import { graceful } from "graceful-process";
5
- import cluster from "node:cluster";
6
- import { cfork } from "cfork";
7
-
8
- //#region src/utils/mode/impl/process/app.ts
9
- var AppProcessWorker = class extends BaseAppWorker {
10
- get id() {
11
- return this.instance.id;
12
- }
13
- get workerId() {
14
- return this.instance.process.pid;
15
- }
16
- get exitedAfterDisconnect() {
17
- return this.instance.exitedAfterDisconnect;
18
- }
19
- get exitCode() {
20
- return this.instance.process.exitCode;
21
- }
22
- send(message) {
23
- sendmessage(this.instance, message);
24
- }
25
- clean() {
26
- this.instance.removeAllListeners();
27
- }
28
- static get workerId() {
29
- return process.pid;
30
- }
31
- static on(event, listener) {
32
- process.on(event, listener);
33
- }
34
- static send(message) {
35
- message.senderWorkerId = String(process.pid);
36
- process.send(message);
37
- }
38
- static kill() {
39
- process.exitCode = 1;
40
- process.kill(process.pid);
41
- }
42
- static gracefulExit(options) {
43
- graceful(options);
44
- }
45
- };
46
- var AppProcessUtils = class extends BaseAppUtils {
47
- fork() {
48
- this.startTime = Date.now();
49
- this.startSuccessCount = 0;
50
- const args = [JSON.stringify(this.options)];
51
- this.log("[master] start appWorker with args %j (process)", args);
52
- cfork({
53
- exec: this.getAppWorkerFile(),
54
- args,
55
- silent: false,
56
- count: this.options.workers,
57
- refork: this.isProduction,
58
- windowsHide: process.platform === "win32"
59
- });
60
- let debugPort = process.debugPort;
61
- cluster.on("fork", (worker) => {
62
- const appWorker = new AppProcessWorker(worker);
63
- this.emit("worker_forked", appWorker);
64
- appWorker.disableRefork = true;
65
- worker.on("message", (msg) => {
66
- if (typeof msg === "string") msg = {
67
- action: msg,
68
- data: msg
69
- };
70
- msg.from = "app";
71
- this.messenger.send(msg);
72
- });
73
- this.log("[master] app_worker#%s:%s start, state: %s, current workers: %j", appWorker.id, appWorker.workerId, appWorker.state, Object.keys(cluster.workers));
74
- if (this.options.isDebug) {
75
- debugPort++;
76
- this.messenger.send({
77
- to: "parent",
78
- from: "app",
79
- action: "debug",
80
- data: {
81
- debugPort,
82
- pid: appWorker.workerId,
83
- workerId: appWorker.workerId
84
- }
85
- });
86
- }
87
- });
88
- cluster.on("disconnect", (worker) => {
89
- const appWorker = new AppProcessWorker(worker);
90
- 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));
91
- });
92
- cluster.on("exit", (worker, code, signal) => {
93
- const appWorker = new AppProcessWorker(worker);
94
- this.messenger.send({
95
- action: "app-exit",
96
- data: {
97
- workerId: appWorker.workerId,
98
- code,
99
- signal
100
- },
101
- to: "master",
102
- from: "app"
103
- });
104
- });
105
- return this;
106
- }
107
- async kill(timeout) {
108
- await Promise.all(Object.keys(cluster.workers).map((id) => {
109
- const worker = cluster.workers[id];
110
- Reflect.set(worker, "disableRefork", true);
111
- return terminate(worker.process, timeout);
112
- }));
113
- }
114
- };
115
-
116
- //#endregion
117
- export { AppProcessUtils, AppProcessWorker };
@@ -1,22 +0,0 @@
1
- import { BaseAgentUtils, BaseAgentWorker } from "../../base/agent.js";
2
- import { MessageBody } from "../../../messenger.js";
3
- import { Worker } from "node:worker_threads";
4
- import { Options } from "graceful-process";
5
-
6
- //#region src/utils/mode/impl/worker_threads/agent.d.ts
7
- declare class AgentThreadWorker extends BaseAgentWorker<Worker> {
8
- get workerId(): number;
9
- send(message: MessageBody): void;
10
- static send(message: MessageBody): void;
11
- static kill(): void;
12
- static gracefulExit(options: Options): void;
13
- }
14
- declare class AgentThreadUtils extends BaseAgentUtils {
15
- #private;
16
- instance: AgentThreadWorker;
17
- fork(): void;
18
- clean(): void;
19
- kill(): Promise<void>;
20
- }
21
- //#endregion
22
- export { AgentThreadUtils };
@@ -1,79 +0,0 @@
1
- import { BaseAgentUtils, BaseAgentWorker } from "../../base/agent.js";
2
- import { ClusterAgentWorkerError } from "../../../../error/ClusterAgentWorkerError.js";
3
- import workerThreads from "node:worker_threads";
4
- import "graceful-process";
5
-
6
- //#region src/utils/mode/impl/worker_threads/agent.ts
7
- var AgentThreadWorker = class extends BaseAgentWorker {
8
- get workerId() {
9
- return this.instance.threadId;
10
- }
11
- send(message) {
12
- this.instance.postMessage(message);
13
- }
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
- };
29
- var AgentThreadUtils = class extends BaseAgentUtils {
30
- #worker;
31
- #id = 0;
32
- instance;
33
- fork() {
34
- this.startTime = Date.now();
35
- const argv = [JSON.stringify(this.options)];
36
- const agentPath = this.getAgentWorkerFile();
37
- const worker = this.#worker = new workerThreads.Worker(agentPath, { argv });
38
- const agentWorker = this.instance = new AgentThreadWorker(worker);
39
- this.emit("agent_forked", agentWorker);
40
- agentWorker.status = "starting";
41
- agentWorker.id = ++this.#id;
42
- this.log("[master] agent_worker#%s:%s start with worker_threads", agentWorker.id, agentWorker.workerId);
43
- worker.on("message", (msg) => {
44
- if (typeof msg === "string") msg = {
45
- action: msg,
46
- data: msg
47
- };
48
- msg.from = "agent";
49
- this.messenger.send(msg);
50
- });
51
- worker.on("error", (err) => {
52
- this.logger.error(new ClusterAgentWorkerError(agentWorker.id, agentWorker.workerId, agentWorker.status, err));
53
- });
54
- worker.once("exit", (code, signal) => {
55
- this.messenger.send({
56
- action: "agent-exit",
57
- data: {
58
- code,
59
- signal
60
- },
61
- to: "master",
62
- from: "agent"
63
- });
64
- });
65
- }
66
- clean() {
67
- this.#worker.removeAllListeners();
68
- }
69
- async kill() {
70
- if (this.#worker) {
71
- this.log(`[master] kill agent worker#${this.#id} (worker_threads) by worker.terminate()`);
72
- this.clean();
73
- await this.#worker.terminate();
74
- }
75
- }
76
- };
77
-
78
- //#endregion
79
- export { AgentThreadUtils, AgentThreadWorker };
@@ -1,13 +0,0 @@
1
- import { BaseAppUtils } from "../../base/app.js";
2
- import { Worker } from "node:worker_threads";
3
- import { Options } from "graceful-process";
4
-
5
- //#region src/utils/mode/impl/worker_threads/app.d.ts
6
-
7
- declare class AppThreadUtils extends BaseAppUtils {
8
- #private;
9
- fork(): this;
10
- kill(): Promise<void>;
11
- }
12
- //#endregion
13
- export { AppThreadUtils };
@@ -1,128 +0,0 @@
1
- import { BaseAppUtils, BaseAppWorker } from "../../base/app.js";
2
- import { Worker, parentPort, threadId } from "node:worker_threads";
3
- import { setTimeout } from "node:timers/promises";
4
-
5
- //#region src/utils/mode/impl/worker_threads/app.ts
6
- var AppThreadWorker = class extends BaseAppWorker {
7
- #state = "none";
8
- #id;
9
- constructor(instance, id) {
10
- super(instance);
11
- this.#id = id;
12
- }
13
- get id() {
14
- return this.#id;
15
- }
16
- get workerId() {
17
- return this.instance.threadId;
18
- }
19
- get state() {
20
- return this.#state;
21
- }
22
- set state(val) {
23
- this.#state = val;
24
- }
25
- get exitedAfterDisconnect() {
26
- return true;
27
- }
28
- get exitCode() {
29
- return 0;
30
- }
31
- send(message) {
32
- this.instance.postMessage(message);
33
- }
34
- clean() {
35
- this.instance.removeAllListeners();
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
- };
57
- var AppThreadUtils = class extends BaseAppUtils {
58
- #workers = [];
59
- #forkSingle(appPath, options, id) {
60
- const worker = new Worker(appPath, options);
61
- this.#workers.push(worker);
62
- const appWorker = new AppThreadWorker(worker, id);
63
- this.emit("worker_forked", appWorker);
64
- appWorker.disableRefork = true;
65
- worker.on("message", (msg) => {
66
- if (typeof msg === "string") msg = {
67
- action: msg,
68
- data: msg
69
- };
70
- msg.from = "app";
71
- this.messenger.send(msg);
72
- });
73
- this.log("[master] app_worker#%s (tid:%s) start", appWorker.id, appWorker.workerId);
74
- let debugPort = process.debugPort;
75
- if (this.options.isDebug) {
76
- debugPort++;
77
- this.messenger.send({
78
- to: "parent",
79
- from: "app",
80
- action: "debug",
81
- data: {
82
- debugPort,
83
- pid: appWorker.workerId,
84
- workerId: appWorker.workerId
85
- }
86
- });
87
- }
88
- worker.on("exit", async (code) => {
89
- appWorker.state = "dead";
90
- this.messenger.send({
91
- action: "app-exit",
92
- data: {
93
- workerId: appWorker.workerId,
94
- code
95
- },
96
- to: "master",
97
- from: "app"
98
- });
99
- await setTimeout(1e3);
100
- this.#forkSingle(appPath, options, id);
101
- });
102
- }
103
- fork() {
104
- this.startTime = Date.now();
105
- this.startSuccessCount = 0;
106
- const ports = this.options.ports ?? [];
107
- if (!ports.length) ports.push(this.options.port);
108
- this.options.workers = ports.length;
109
- let i = 0;
110
- do {
111
- const options = Object.assign({}, this.options, { port: ports[i] });
112
- const argv = [JSON.stringify(options)];
113
- this.#forkSingle(this.getAppWorkerFile(), { argv }, ++i);
114
- } while (i < ports.length);
115
- return this;
116
- }
117
- async kill() {
118
- for (const worker of this.#workers) {
119
- const id = Reflect.get(worker, "id");
120
- this.log(`[master] kill app worker#${id} (worker_threads) by worker.terminate()`);
121
- worker.removeAllListeners();
122
- worker.terminate();
123
- }
124
- }
125
- };
126
-
127
- //#endregion
128
- export { AppThreadUtils, AppThreadWorker };
@@ -1,83 +0,0 @@
1
- import { SecureContextOptions } from "node:tls";
2
-
3
- //#region src/utils/options.d.ts
4
- interface ClusterHTTPSSecureOptions {
5
- key: SecureContextOptions['key'];
6
- cert: SecureContextOptions['cert'];
7
- ca?: SecureContextOptions['ca'];
8
- passphrase?: SecureContextOptions['passphrase'];
9
- }
10
- type ClusterStartMode = 'process' | 'worker_threads';
11
- /** Cluster start options */
12
- interface ClusterOptions {
13
- /**
14
- * specify framework that can be absolute path or npm package
15
- */
16
- framework?: string;
17
- /**
18
- * @deprecated please use framework instead
19
- */
20
- customEgg?: string;
21
- /** directory of application, default to `process.cwd()` */
22
- baseDir?: string;
23
- /**
24
- * numbers of app workers, default to `os.cpus().length`
25
- */
26
- workers?: number | string;
27
- /**
28
- * listening port, default to `7001`(http) or `8443`(https)
29
- */
30
- port?: number | string | null;
31
- /**
32
- * listening a debug port on http protocol
33
- */
34
- debugPort?: number;
35
- /**
36
- * https options, { key, cert, ca }, full path
37
- */
38
- https?: ClusterHTTPSSecureOptions | boolean;
39
- /**
40
- * @deprecated please use `options.https.key` instead
41
- */
42
- key?: ClusterHTTPSSecureOptions['key'];
43
- /**
44
- * @deprecated please use `options.https.cert` instead
45
- */
46
- cert?: ClusterHTTPSSecureOptions['cert'];
47
- /**
48
- * will inject into worker/agent process
49
- */
50
- require?: string | string[];
51
- /**
52
- * will save master pid to this file
53
- */
54
- pidFile?: string;
55
- /**
56
- * custom env, default is `process.env.EGG_SERVER_ENV`
57
- */
58
- env?: string;
59
- /**
60
- * default is `'process'`, use `'worker_threads'` to start the app & agent worker by worker_threads
61
- */
62
- startMode?: ClusterStartMode;
63
- /**
64
- * startup port of each app worker, such as: `[7001, 7002, 7003]`, only effects when the startMode is `'worker_threads'`
65
- */
66
- ports?: number[];
67
- /**
68
- * sticky mode server
69
- */
70
- sticky?: boolean;
71
- /** customized plugins, for unittest */
72
- plugins?: object;
73
- isDebug?: boolean;
74
- }
75
- interface ParsedClusterOptions extends ClusterOptions {
76
- port?: number;
77
- baseDir: string;
78
- workers: number;
79
- framework: string;
80
- startMode: ClusterStartMode;
81
- }
82
- //#endregion
83
- export { ClusterHTTPSSecureOptions, ClusterOptions, ClusterStartMode, ParsedClusterOptions };
@@ -1,56 +0,0 @@
1
- import os from "node:os";
2
- import { debuglog } from "node:util";
3
- import path from "node:path";
4
- import fs from "node:fs";
5
- import assert from "node:assert";
6
- import { getFrameworkPath, importModule } from "@eggjs/utils";
7
-
8
- //#region src/utils/options.ts
9
- const debug = debuglog("egg/cluster/utils/options");
10
- async function parseOptions(options) {
11
- options = {
12
- baseDir: process.cwd(),
13
- port: options?.https ? 8443 : void 0,
14
- startMode: "process",
15
- env: process.env.EGG_SERVER_ENV,
16
- ...options
17
- };
18
- const pkgPath = path.join(options.baseDir, "package.json");
19
- assert(fs.existsSync(pkgPath), `${pkgPath} should exist`);
20
- options.framework = getFrameworkPath({
21
- baseDir: options.baseDir,
22
- framework: options.framework ?? options.customEgg
23
- });
24
- debug("[parseOptions] %o", options);
25
- const egg = await importModule(options.framework, { paths: [options.baseDir] });
26
- assert(egg.Application, `should define Application in ${options.framework}`);
27
- assert(egg.Agent, `should define Agent in ${options.framework}`);
28
- if (options.https === true) {
29
- console.warn("[@eggjs/cluster:deprecated] [master] Please use `https: { key, cert, ca }` instead of `https: true`");
30
- options.https = {
31
- key: options.key,
32
- cert: options.cert
33
- };
34
- }
35
- if (options.https) {
36
- assert(options.https.key, "options.https.key should exists");
37
- if (typeof options.https.key === "string") assert(fs.existsSync(options.https.key), "options.https.key file should exists");
38
- assert(options.https.cert, "options.https.cert should exists");
39
- if (typeof options.https.cert === "string") assert(fs.existsSync(options.https.cert), "options.https.cert file should exists");
40
- if (typeof options.https.ca === "string") assert(fs.existsSync(options.https.ca), "options.https.ca file should exists");
41
- }
42
- if (options.port && typeof options.port === "string") options.port = parseInt(options.port);
43
- if (options.port === null) options.port = void 0;
44
- if (options.workers && typeof options.workers === "string") options.workers = parseInt(options.workers);
45
- if (!options.workers) options.workers = os.cpus().length;
46
- if (options.require) {
47
- if (typeof options.require === "string") options.require = [options.require];
48
- }
49
- if (process.env.NODE_ENV === "production") process.env.NO_DEPRECATION = "*";
50
- const isDebug = process.execArgv.some((argv) => argv.includes("--debug") || argv.includes("--inspect"));
51
- if (isDebug) options.isDebug = isDebug;
52
- return options;
53
- }
54
-
55
- //#endregion
56
- export { parseOptions };
@@ -1,32 +0,0 @@
1
- import { BaseAgentWorker } from "./mode/base/agent.js";
2
- import { BaseAppWorker } from "./mode/base/app.js";
3
- import { EventEmitter } from "node:events";
4
- import * as worker_threads0 from "worker_threads";
5
- import * as cluster0 from "cluster";
6
- import * as child_process0 from "child_process";
7
-
8
- //#region src/utils/worker_manager.d.ts
9
- declare class WorkerManager extends EventEmitter {
10
- agent: BaseAgentWorker | null;
11
- workers: Map<number, BaseAppWorker<worker_threads0.Worker | cluster0.Worker>>;
12
- exception: number;
13
- timer: NodeJS.Timeout;
14
- constructor();
15
- getWorkers(): number[];
16
- setAgent(agent: BaseAgentWorker): void;
17
- getAgent(): BaseAgentWorker<worker_threads0.Worker | child_process0.ChildProcess> | null;
18
- deleteAgent(): void;
19
- setWorker(worker: BaseAppWorker): void;
20
- getWorker(workerId: number): BaseAppWorker<worker_threads0.Worker | cluster0.Worker> | undefined;
21
- deleteWorker(workerId: number): void;
22
- listWorkerIds(): number[];
23
- listWorkers(): BaseAppWorker<worker_threads0.Worker | cluster0.Worker>[];
24
- getListeningWorkerIds(): number[];
25
- count(): {
26
- agent: number;
27
- worker: number;
28
- };
29
- startCheck(): void;
30
- }
31
- //#endregion
32
- export { WorkerManager };
@@ -1,68 +0,0 @@
1
- import { EventEmitter } from "node:events";
2
-
3
- //#region src/utils/worker_manager.ts
4
- var WorkerManager = class extends EventEmitter {
5
- agent;
6
- workers = /* @__PURE__ */ new Map();
7
- exception = 0;
8
- timer;
9
- constructor() {
10
- super();
11
- this.agent = null;
12
- }
13
- getWorkers() {
14
- return Array.from(this.workers.keys());
15
- }
16
- setAgent(agent) {
17
- this.agent = agent;
18
- }
19
- getAgent() {
20
- return this.agent;
21
- }
22
- deleteAgent() {
23
- this.agent = null;
24
- }
25
- setWorker(worker) {
26
- this.workers.set(worker.workerId, worker);
27
- }
28
- getWorker(workerId) {
29
- return this.workers.get(workerId);
30
- }
31
- deleteWorker(workerId) {
32
- this.workers.delete(workerId);
33
- }
34
- listWorkerIds() {
35
- return Array.from(this.workers.keys());
36
- }
37
- listWorkers() {
38
- return Array.from(this.workers.values());
39
- }
40
- getListeningWorkerIds() {
41
- const keys = [];
42
- for (const [id, worker] of this.workers.entries()) if (worker.state === "listening") keys.push(id);
43
- return keys;
44
- }
45
- count() {
46
- return {
47
- agent: this.agent?.status === "started" ? 1 : 0,
48
- worker: this.listWorkerIds().length
49
- };
50
- }
51
- startCheck() {
52
- this.timer = setInterval(() => {
53
- const count = this.count();
54
- if (count.agent > 0 && count.worker > 0) {
55
- this.exception = 0;
56
- return;
57
- }
58
- this.exception++;
59
- if (this.exception >= 3) {
60
- this.emit("exception", count);
61
- clearInterval(this.timer);
62
- }
63
- }, 1e4);
64
- }
65
- };
66
-
67
- //#endregion
68
- export { WorkerManager };