@eggjs/cluster 3.0.1 → 3.1.0-beta.10

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 (123) hide show
  1. package/README.md +17 -21
  2. package/dist/dirname.js +11 -0
  3. package/dist/error/ClusterAgentWorkerError.d.ts +13 -0
  4. package/dist/error/ClusterAgentWorkerError.js +22 -0
  5. package/dist/error/ClusterWorkerExceptionError.d.ts +10 -0
  6. package/dist/error/ClusterWorkerExceptionError.js +17 -0
  7. package/dist/index.d.ts +22 -0
  8. package/dist/index.js +24 -0
  9. package/dist/master.d.ts +96 -0
  10. package/dist/master.js +426 -0
  11. package/dist/utils/messenger.d.ts +96 -0
  12. package/dist/utils/messenger.js +144 -0
  13. package/dist/utils/mode/base/agent.d.ts +45 -0
  14. package/dist/utils/mode/base/agent.js +63 -0
  15. package/dist/utils/mode/base/app.d.ts +56 -0
  16. package/dist/utils/mode/base/app.js +77 -0
  17. package/dist/utils/mode/impl/process/agent.d.ts +22 -0
  18. package/dist/utils/mode/impl/process/agent.js +93 -0
  19. package/dist/utils/mode/impl/process/app.d.ts +12 -0
  20. package/dist/utils/mode/impl/process/app.js +117 -0
  21. package/dist/utils/mode/impl/worker_threads/agent.d.ts +22 -0
  22. package/dist/utils/mode/impl/worker_threads/agent.js +79 -0
  23. package/dist/utils/mode/impl/worker_threads/app.d.ts +13 -0
  24. package/dist/utils/mode/impl/worker_threads/app.js +128 -0
  25. package/dist/utils/options.d.ts +83 -0
  26. package/dist/utils/options.js +56 -0
  27. package/dist/utils/terminate.js +62 -0
  28. package/dist/utils/worker_manager.d.ts +32 -0
  29. package/dist/utils/worker_manager.js +68 -0
  30. package/package.json +39 -63
  31. package/dist/commonjs/agent_worker.d.ts +0 -1
  32. package/dist/commonjs/agent_worker.js +0 -69
  33. package/dist/commonjs/app_worker.d.ts +0 -1
  34. package/dist/commonjs/app_worker.js +0 -173
  35. package/dist/commonjs/dirname.d.ts +0 -1
  36. package/dist/commonjs/dirname.js +0 -17
  37. package/dist/commonjs/error/ClusterAgentWorkerError.d.ts +0 -10
  38. package/dist/commonjs/error/ClusterAgentWorkerError.js +0 -23
  39. package/dist/commonjs/error/ClusterWorkerExceptionError.d.ts +0 -7
  40. package/dist/commonjs/error/ClusterWorkerExceptionError.js +0 -18
  41. package/dist/commonjs/error/index.d.ts +0 -2
  42. package/dist/commonjs/error/index.js +0 -19
  43. package/dist/commonjs/index.d.ts +0 -17
  44. package/dist/commonjs/index.js +0 -37
  45. package/dist/commonjs/master.d.ts +0 -90
  46. package/dist/commonjs/master.js +0 -560
  47. package/dist/commonjs/package.json +0 -3
  48. package/dist/commonjs/utils/messenger.d.ts +0 -92
  49. package/dist/commonjs/utils/messenger.js +0 -186
  50. package/dist/commonjs/utils/mode/base/agent.d.ts +0 -38
  51. package/dist/commonjs/utils/mode/base/agent.js +0 -68
  52. package/dist/commonjs/utils/mode/base/app.d.ts +0 -48
  53. package/dist/commonjs/utils/mode/base/app.js +0 -83
  54. package/dist/commonjs/utils/mode/impl/process/agent.d.ts +0 -18
  55. package/dist/commonjs/utils/mode/impl/process/agent.js +0 -108
  56. package/dist/commonjs/utils/mode/impl/process/app.d.ts +0 -21
  57. package/dist/commonjs/utils/mode/impl/process/app.js +0 -127
  58. package/dist/commonjs/utils/mode/impl/worker_threads/agent.d.ts +0 -18
  59. package/dist/commonjs/utils/mode/impl/worker_threads/agent.js +0 -91
  60. package/dist/commonjs/utils/mode/impl/worker_threads/app.d.ts +0 -26
  61. package/dist/commonjs/utils/mode/impl/worker_threads/app.js +0 -142
  62. package/dist/commonjs/utils/options.d.ts +0 -80
  63. package/dist/commonjs/utils/options.js +0 -83
  64. package/dist/commonjs/utils/terminate.d.ts +0 -6
  65. package/dist/commonjs/utils/terminate.js +0 -89
  66. package/dist/commonjs/utils/worker_manager.d.ts +0 -25
  67. package/dist/commonjs/utils/worker_manager.js +0 -76
  68. package/dist/esm/agent_worker.d.ts +0 -1
  69. package/dist/esm/agent_worker.js +0 -67
  70. package/dist/esm/app_worker.d.ts +0 -1
  71. package/dist/esm/app_worker.js +0 -168
  72. package/dist/esm/dirname.d.ts +0 -1
  73. package/dist/esm/dirname.js +0 -11
  74. package/dist/esm/error/ClusterAgentWorkerError.d.ts +0 -10
  75. package/dist/esm/error/ClusterAgentWorkerError.js +0 -19
  76. package/dist/esm/error/ClusterWorkerExceptionError.d.ts +0 -7
  77. package/dist/esm/error/ClusterWorkerExceptionError.js +0 -14
  78. package/dist/esm/error/index.d.ts +0 -2
  79. package/dist/esm/error/index.js +0 -3
  80. package/dist/esm/index.d.ts +0 -17
  81. package/dist/esm/index.js +0 -19
  82. package/dist/esm/master.d.ts +0 -90
  83. package/dist/esm/master.js +0 -553
  84. package/dist/esm/package.json +0 -3
  85. package/dist/esm/utils/messenger.d.ts +0 -92
  86. package/dist/esm/utils/messenger.js +0 -179
  87. package/dist/esm/utils/mode/base/agent.d.ts +0 -38
  88. package/dist/esm/utils/mode/base/agent.js +0 -60
  89. package/dist/esm/utils/mode/base/app.d.ts +0 -48
  90. package/dist/esm/utils/mode/base/app.js +0 -75
  91. package/dist/esm/utils/mode/impl/process/agent.d.ts +0 -18
  92. package/dist/esm/utils/mode/impl/process/agent.js +0 -103
  93. package/dist/esm/utils/mode/impl/process/app.d.ts +0 -21
  94. package/dist/esm/utils/mode/impl/process/app.js +0 -119
  95. package/dist/esm/utils/mode/impl/worker_threads/agent.d.ts +0 -18
  96. package/dist/esm/utils/mode/impl/worker_threads/agent.js +0 -83
  97. package/dist/esm/utils/mode/impl/worker_threads/app.d.ts +0 -26
  98. package/dist/esm/utils/mode/impl/worker_threads/app.js +0 -137
  99. package/dist/esm/utils/options.d.ts +0 -80
  100. package/dist/esm/utils/options.js +0 -77
  101. package/dist/esm/utils/terminate.d.ts +0 -6
  102. package/dist/esm/utils/terminate.js +0 -86
  103. package/dist/esm/utils/worker_manager.d.ts +0 -25
  104. package/dist/esm/utils/worker_manager.js +0 -72
  105. package/dist/package.json +0 -4
  106. package/src/agent_worker.ts +0 -80
  107. package/src/app_worker.ts +0 -196
  108. package/src/dirname.ts +0 -11
  109. package/src/error/ClusterAgentWorkerError.ts +0 -19
  110. package/src/error/ClusterWorkerExceptionError.ts +0 -17
  111. package/src/error/index.ts +0 -2
  112. package/src/index.ts +0 -26
  113. package/src/master.ts +0 -658
  114. package/src/utils/messenger.ts +0 -207
  115. package/src/utils/mode/base/agent.ts +0 -90
  116. package/src/utils/mode/base/app.ts +0 -119
  117. package/src/utils/mode/impl/process/agent.ts +0 -119
  118. package/src/utils/mode/impl/process/app.ts +0 -140
  119. package/src/utils/mode/impl/worker_threads/agent.ts +0 -99
  120. package/src/utils/mode/impl/worker_threads/app.ts +0 -164
  121. package/src/utils/options.ts +0 -171
  122. package/src/utils/terminate.ts +0 -97
  123. package/src/utils/worker_manager.ts +0 -87
@@ -0,0 +1,63 @@
1
+ import { getSrcDirname } from "../../../dirname.js";
2
+ import path from "node:path";
3
+ import { existsSync } from "node:fs";
4
+ import { EventEmitter } from "node:events";
5
+
6
+ //#region src/utils/mode/base/agent.ts
7
+ var BaseAgentWorker = class {
8
+ instance;
9
+ #instanceId;
10
+ #instanceStatus;
11
+ constructor(instance) {
12
+ this.instance = instance;
13
+ }
14
+ get id() {
15
+ return this.#instanceId;
16
+ }
17
+ set id(id) {
18
+ this.#instanceId = id;
19
+ }
20
+ get status() {
21
+ return this.#instanceStatus;
22
+ }
23
+ set status(status) {
24
+ this.#instanceStatus = status;
25
+ }
26
+ static send(_message) {
27
+ throw new Error("BaseAgentWorker should implement send.");
28
+ }
29
+ static kill() {
30
+ throw new Error("BaseAgentWorker should implement kill.");
31
+ }
32
+ static gracefulExit(_options) {
33
+ throw new Error("BaseAgentWorker should implement gracefulExit.");
34
+ }
35
+ };
36
+ var BaseAgentUtils = class extends EventEmitter {
37
+ options;
38
+ messenger;
39
+ log;
40
+ logger;
41
+ startTime = 0;
42
+ constructor(options, { log, logger, messenger }) {
43
+ super();
44
+ this.options = options;
45
+ this.log = log;
46
+ this.logger = logger;
47
+ this.messenger = messenger;
48
+ }
49
+ getAgentWorkerFile() {
50
+ let agentWorkerFile = path.join(getSrcDirname(), "agent_worker.js");
51
+ if (!existsSync(agentWorkerFile)) agentWorkerFile = path.join(getSrcDirname(), "agent_worker.ts");
52
+ return agentWorkerFile;
53
+ }
54
+ fork() {
55
+ throw new Error("BaseAgent should implement fork.");
56
+ }
57
+ clean() {
58
+ throw new Error("BaseAgent should implement clean.");
59
+ }
60
+ };
61
+
62
+ //#endregion
63
+ export { BaseAgentUtils, BaseAgentWorker };
@@ -0,0 +1,56 @@
1
+ import { MessageBody, Messenger } from "../../messenger.js";
2
+ import { MasterOptions } from "../../../master.js";
3
+ import { Logger } from "egg-logger";
4
+ import { EventEmitter } from "node:events";
5
+ import { Worker } from "node:worker_threads";
6
+ import { Worker as Worker$1 } from "node:cluster";
7
+
8
+ //#region src/utils/mode/base/app.d.ts
9
+ declare abstract class BaseAppWorker<T = Worker | Worker$1> {
10
+ instance: T;
11
+ constructor(instance: T);
12
+ abstract get workerId(): number;
13
+ abstract get id(): number;
14
+ get state(): string;
15
+ set state(state: string);
16
+ abstract get exitedAfterDisconnect(): boolean;
17
+ abstract get exitCode(): number;
18
+ get disableRefork(): boolean;
19
+ set disableRefork(disableRefork: boolean);
20
+ get isDevReload(): boolean;
21
+ set isDevReload(isDevReload: boolean);
22
+ abstract send(data: MessageBody): void;
23
+ clean(): void;
24
+ static get workerId(): number;
25
+ static on(..._args: any[]): void;
26
+ static send(_message: MessageBody): void;
27
+ static kill(): void;
28
+ static gracefulExit(_options: any): void;
29
+ }
30
+ type LogFun = (msg: any, ...args: any[]) => void;
31
+ declare abstract class BaseAppUtils extends EventEmitter {
32
+ options: MasterOptions;
33
+ protected messenger: Messenger;
34
+ protected log: LogFun;
35
+ protected logger: Logger;
36
+ protected isProduction: boolean;
37
+ startTime: number;
38
+ startSuccessCount: number;
39
+ isAllWorkerStarted: boolean;
40
+ constructor(options: MasterOptions, {
41
+ log,
42
+ logger,
43
+ messenger,
44
+ isProduction
45
+ }: {
46
+ log: LogFun;
47
+ logger: Logger;
48
+ messenger: Messenger;
49
+ isProduction: boolean;
50
+ });
51
+ getAppWorkerFile(): string;
52
+ fork(): void;
53
+ abstract kill(timeout: number): Promise<void>;
54
+ }
55
+ //#endregion
56
+ export { BaseAppUtils, BaseAppWorker };
@@ -0,0 +1,77 @@
1
+ import { getSrcDirname } from "../../../dirname.js";
2
+ import path from "node:path";
3
+ import { existsSync } from "node:fs";
4
+ import { EventEmitter } from "node:events";
5
+
6
+ //#region src/utils/mode/base/app.ts
7
+ var BaseAppWorker = class {
8
+ instance;
9
+ constructor(instance) {
10
+ this.instance = instance;
11
+ }
12
+ get state() {
13
+ return Reflect.get(this.instance, "state");
14
+ }
15
+ set state(state) {
16
+ Reflect.set(this.instance, "state", state);
17
+ }
18
+ get disableRefork() {
19
+ return Reflect.get(this.instance, "disableRefork");
20
+ }
21
+ set disableRefork(disableRefork) {
22
+ Reflect.set(this.instance, "disableRefork", disableRefork);
23
+ }
24
+ get isDevReload() {
25
+ return Reflect.get(this.instance, "isDevReload");
26
+ }
27
+ set isDevReload(isDevReload) {
28
+ Reflect.set(this.instance, "isDevReload", isDevReload);
29
+ }
30
+ clean() {
31
+ throw new Error("BaseAppWorker should implement clean.");
32
+ }
33
+ static get workerId() {
34
+ throw new Error("BaseAppWorker should implement workerId.");
35
+ }
36
+ static on(..._args) {
37
+ throw new Error("BaseAppWorker should implement on.");
38
+ }
39
+ static send(_message) {
40
+ throw new Error("BaseAgentWorker should implement send.");
41
+ }
42
+ static kill() {
43
+ throw new Error("BaseAppWorker should implement kill.");
44
+ }
45
+ static gracefulExit(_options) {
46
+ throw new Error("BaseAgentWorker should implement gracefulExit.");
47
+ }
48
+ };
49
+ var BaseAppUtils = class extends EventEmitter {
50
+ options;
51
+ messenger;
52
+ log;
53
+ logger;
54
+ isProduction;
55
+ startTime = 0;
56
+ startSuccessCount = 0;
57
+ isAllWorkerStarted = false;
58
+ constructor(options, { log, logger, messenger, isProduction }) {
59
+ super();
60
+ this.options = options;
61
+ this.log = log;
62
+ this.logger = logger;
63
+ this.messenger = messenger;
64
+ this.isProduction = isProduction;
65
+ }
66
+ getAppWorkerFile() {
67
+ let appWorkerFile = path.join(getSrcDirname(), "app_worker.js");
68
+ if (!existsSync(appWorkerFile)) appWorkerFile = path.join(getSrcDirname(), "app_worker.ts");
69
+ return appWorkerFile;
70
+ }
71
+ fork() {
72
+ throw new Error("BaseApp should implement fork.");
73
+ }
74
+ };
75
+
76
+ //#endregion
77
+ export { BaseAppUtils, BaseAppWorker };
@@ -0,0 +1,22 @@
1
+ import { BaseAgentUtils, BaseAgentWorker } from "../../base/agent.js";
2
+ import { MessageBody } from "../../../messenger.js";
3
+ import { ChildProcess } from "node:child_process";
4
+ import { Options } from "graceful-process";
5
+
6
+ //#region src/utils/mode/impl/process/agent.d.ts
7
+ declare class AgentProcessWorker extends BaseAgentWorker<ChildProcess> {
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 AgentProcessUtils extends BaseAgentUtils {
15
+ #private;
16
+ instance: AgentProcessWorker;
17
+ fork(): this;
18
+ clean(): void;
19
+ kill(timeout: number): Promise<void>;
20
+ }
21
+ //#endregion
22
+ export { AgentProcessUtils };
@@ -0,0 +1,93 @@
1
+ import { BaseAgentUtils, BaseAgentWorker } from "../../base/agent.js";
2
+ import { terminate } from "../../../terminate.js";
3
+ import { ClusterAgentWorkerError } from "../../../../error/ClusterAgentWorkerError.js";
4
+ import { fork } from "node:child_process";
5
+ import { sendmessage } from "sendmessage";
6
+ import { graceful } from "graceful-process";
7
+
8
+ //#region src/utils/mode/impl/process/agent.ts
9
+ var AgentProcessWorker = class extends BaseAgentWorker {
10
+ get workerId() {
11
+ return this.instance.pid;
12
+ }
13
+ send(message) {
14
+ sendmessage(this.instance, message);
15
+ }
16
+ static send(message) {
17
+ message.senderWorkerId = String(process.pid);
18
+ process.send(message);
19
+ }
20
+ static kill() {
21
+ process.exitCode = 1;
22
+ process.kill(process.pid);
23
+ }
24
+ static gracefulExit(options) {
25
+ graceful(options);
26
+ }
27
+ };
28
+ var AgentProcessUtils = class extends BaseAgentUtils {
29
+ #agentProcess;
30
+ #id = 0;
31
+ instance;
32
+ fork() {
33
+ this.startTime = Date.now();
34
+ const args = [JSON.stringify(this.options)];
35
+ const forkOptions = {};
36
+ if (process.platform === "win32") forkOptions.windowsHide = true;
37
+ const debugPort = process.env.EGG_AGENT_DEBUG_PORT ?? 5800;
38
+ if (this.options.isDebug) forkOptions.execArgv = process.execArgv.concat([`--inspect-port=${debugPort}`]);
39
+ const agentProcess = this.#agentProcess = fork(this.getAgentWorkerFile(), args, forkOptions);
40
+ const agentWorker = this.instance = new AgentProcessWorker(agentProcess);
41
+ agentWorker.status = "starting";
42
+ agentWorker.id = ++this.#id;
43
+ this.emit("agent_forked", agentWorker);
44
+ this.log("[master] agent_worker#%s:%s start with clusterPort:%s", agentWorker.id, agentWorker.workerId, this.options.clusterPort);
45
+ if (this.options.isDebug) this.messenger.send({
46
+ to: "parent",
47
+ from: "agent",
48
+ action: "debug",
49
+ data: {
50
+ debugPort,
51
+ pid: agentWorker.workerId,
52
+ workerId: agentWorker.workerId
53
+ }
54
+ });
55
+ agentProcess.on("message", (msg) => {
56
+ if (typeof msg === "string") msg = {
57
+ action: msg,
58
+ data: msg
59
+ };
60
+ msg.from = "agent";
61
+ this.messenger.send(msg);
62
+ });
63
+ agentProcess.on("error", (err) => {
64
+ err.name = "AgentWorkerError";
65
+ this.logger.error(new ClusterAgentWorkerError(agentWorker.id, agentWorker.workerId, agentWorker.status, err));
66
+ });
67
+ agentProcess.once("exit", (code, signal) => {
68
+ this.messenger.send({
69
+ action: "agent-exit",
70
+ data: {
71
+ code,
72
+ signal
73
+ },
74
+ to: "master",
75
+ from: "agent"
76
+ });
77
+ });
78
+ return this;
79
+ }
80
+ clean() {
81
+ this.#agentProcess.removeAllListeners();
82
+ }
83
+ async kill(timeout) {
84
+ if (this.#agentProcess) {
85
+ this.log("[master] kill agent worker with signal SIGTERM");
86
+ this.clean();
87
+ await terminate(this.#agentProcess, timeout);
88
+ }
89
+ }
90
+ };
91
+
92
+ //#endregion
93
+ export { AgentProcessUtils };
@@ -0,0 +1,12 @@
1
+ import { BaseAppUtils } from "../../base/app.js";
2
+ import { Options } from "graceful-process";
3
+ import { Worker } from "node:cluster";
4
+
5
+ //#region src/utils/mode/impl/process/app.d.ts
6
+
7
+ declare class AppProcessUtils extends BaseAppUtils {
8
+ fork(): this;
9
+ kill(timeout: number): Promise<void>;
10
+ }
11
+ //#endregion
12
+ export { AppProcessUtils };
@@ -0,0 +1,117 @@
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 };
@@ -0,0 +1,22 @@
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 };
@@ -0,0 +1,79 @@
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 };
@@ -0,0 +1,13 @@
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 };
@@ -0,0 +1,128 @@
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 };