@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
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { debuglog } from 'node:util';
|
|
2
|
+
import { setTimeout as sleep } from 'node:timers/promises';
|
|
3
|
+
import { once } from 'node:events';
|
|
4
|
+
import { ChildProcess } from 'node:child_process';
|
|
5
|
+
import { pstree } from '@fengmk2/ps-tree';
|
|
6
|
+
const debug = debuglog('egg/cluster/utils/terminate');
|
|
7
|
+
export async function terminate(subProcess, timeout) {
|
|
8
|
+
const pid = subProcess.process?.pid ?? subProcess.pid;
|
|
9
|
+
const childPids = await getChildPids(pid);
|
|
10
|
+
await Promise.all([killProcess(subProcess, timeout), killChildren(childPids, timeout)]);
|
|
11
|
+
}
|
|
12
|
+
// kill process, if SIGTERM not work, try SIGKILL
|
|
13
|
+
async function killProcess(subProcess, timeout) {
|
|
14
|
+
// https://github.com/nodejs/node/pull/34312
|
|
15
|
+
(subProcess.process ?? subProcess).kill('SIGTERM');
|
|
16
|
+
await Promise.race([once(subProcess, 'exit'), sleep(timeout)]);
|
|
17
|
+
if (subProcess.killed) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
// SIGKILL: http://man7.org/linux/man-pages/man7/signal.7.html
|
|
21
|
+
// worker: https://github.com/nodejs/node/blob/master/lib/internal/cluster/worker.js#L22
|
|
22
|
+
// subProcess.kill is wrapped to subProcess.destroy, it will wait to disconnected.
|
|
23
|
+
(subProcess.process ?? subProcess).kill('SIGKILL');
|
|
24
|
+
}
|
|
25
|
+
// kill all children processes, if SIGTERM not work, try SIGKILL
|
|
26
|
+
async function killChildren(childrenPids, timeout) {
|
|
27
|
+
if (childrenPids.length === 0) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
kill(childrenPids, 'SIGTERM');
|
|
31
|
+
const start = Date.now();
|
|
32
|
+
// if timeout is 1000, it will check twice.
|
|
33
|
+
const checkInterval = 400;
|
|
34
|
+
let unterminated = [];
|
|
35
|
+
while (Date.now() - start < timeout - checkInterval) {
|
|
36
|
+
await sleep(checkInterval);
|
|
37
|
+
unterminated = getUnterminatedProcesses(childrenPids);
|
|
38
|
+
if (unterminated.length === 0) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
kill(unterminated, 'SIGKILL');
|
|
43
|
+
}
|
|
44
|
+
async function getChildPids(pid) {
|
|
45
|
+
let childrenPids = [];
|
|
46
|
+
try {
|
|
47
|
+
const children = await pstree(pid);
|
|
48
|
+
childrenPids = children.map(c => parseInt(c.PID));
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
// if get children error, just ignore it
|
|
52
|
+
debug('pstree %s error: %s, ignore it', pid, err);
|
|
53
|
+
}
|
|
54
|
+
return childrenPids;
|
|
55
|
+
}
|
|
56
|
+
function kill(pids, signal) {
|
|
57
|
+
for (const pid of pids) {
|
|
58
|
+
try {
|
|
59
|
+
process.kill(pid, signal);
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
// ignore
|
|
63
|
+
debug('kill %s error: %s, signal: %s, ignore it', pid, err, signal);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function getUnterminatedProcesses(pids) {
|
|
68
|
+
return pids.filter(pid => {
|
|
69
|
+
try {
|
|
70
|
+
// success means it's still alive
|
|
71
|
+
process.kill(pid, 0);
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
// error means it's dead
|
|
76
|
+
debug('kill %s error: %s, it still alive', pid, err);
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVybWluYXRlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3V0aWxzL3Rlcm1pbmF0ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBQ3JDLE9BQU8sRUFBRSxVQUFVLElBQUksS0FBSyxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDM0QsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUNuQyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFFbEQsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBRTFDLE1BQU0sS0FBSyxHQUFHLFFBQVEsQ0FBQyw2QkFBNkIsQ0FBQyxDQUFDO0FBTXRELE1BQU0sQ0FBQyxLQUFLLFVBQVUsU0FBUyxDQUFDLFVBQXNCLEVBQUUsT0FBZTtJQUNyRSxNQUFNLEdBQUcsR0FBRyxVQUFVLENBQUMsT0FBTyxFQUFFLEdBQUcsSUFBSSxVQUFVLENBQUMsR0FBRyxDQUFDO0lBQ3RELE1BQU0sU0FBUyxHQUFHLE1BQU0sWUFBWSxDQUFDLEdBQUksQ0FBQyxDQUFDO0lBQzNDLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLFdBQVcsQ0FBQyxVQUFVLEVBQUUsT0FBTyxDQUFDLEVBQUUsWUFBWSxDQUFDLFNBQVMsRUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDMUYsQ0FBQztBQUVELGlEQUFpRDtBQUNqRCxLQUFLLFVBQVUsV0FBVyxDQUFDLFVBQXNCLEVBQUUsT0FBZTtJQUNoRSw0Q0FBNEM7SUFDNUMsQ0FBQyxVQUFVLENBQUMsT0FBTyxJQUFJLFVBQVUsQ0FBQyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUNuRCxNQUFNLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLE1BQU0sQ0FBQyxFQUFFLEtBQUss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
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
import { BaseAgentWorker } from './mode/base/agent.ts';
|
|
3
|
+
import { BaseAppWorker } from './mode/base/app.ts';
|
|
4
|
+
export declare class WorkerManager extends EventEmitter {
|
|
5
|
+
agent: BaseAgentWorker | null;
|
|
6
|
+
workers: Map<number, BaseAppWorker<import("worker_threads").Worker | import("cluster").Worker>>;
|
|
7
|
+
exception: number;
|
|
8
|
+
timer: NodeJS.Timeout;
|
|
9
|
+
constructor();
|
|
10
|
+
getWorkers(): number[];
|
|
11
|
+
setAgent(agent: BaseAgentWorker): void;
|
|
12
|
+
getAgent(): BaseAgentWorker<import("child_process").ChildProcess | import("worker_threads").Worker> | null;
|
|
13
|
+
deleteAgent(): void;
|
|
14
|
+
setWorker(worker: BaseAppWorker): void;
|
|
15
|
+
getWorker(workerId: number): BaseAppWorker<import("worker_threads").Worker | import("cluster").Worker> | undefined;
|
|
16
|
+
deleteWorker(workerId: number): void;
|
|
17
|
+
listWorkerIds(): number[];
|
|
18
|
+
listWorkers(): BaseAppWorker<import("worker_threads").Worker | import("cluster").Worker>[];
|
|
19
|
+
getListeningWorkerIds(): number[];
|
|
20
|
+
count(): {
|
|
21
|
+
agent: number;
|
|
22
|
+
worker: number;
|
|
23
|
+
};
|
|
24
|
+
startCheck(): void;
|
|
25
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
import { BaseAgentWorker } from "./mode/base/agent.js";
|
|
3
|
+
import { BaseAppWorker } from "./mode/base/app.js";
|
|
4
|
+
// worker manager to record agent and worker forked by egg-cluster
|
|
5
|
+
// can do some check stuff here to monitor the healthy
|
|
6
|
+
export class WorkerManager extends EventEmitter {
|
|
7
|
+
agent;
|
|
8
|
+
workers = new Map();
|
|
9
|
+
exception = 0;
|
|
10
|
+
timer;
|
|
11
|
+
constructor() {
|
|
12
|
+
super();
|
|
13
|
+
this.agent = null;
|
|
14
|
+
}
|
|
15
|
+
getWorkers() {
|
|
16
|
+
return Array.from(this.workers.keys());
|
|
17
|
+
}
|
|
18
|
+
setAgent(agent) {
|
|
19
|
+
this.agent = agent;
|
|
20
|
+
}
|
|
21
|
+
getAgent() {
|
|
22
|
+
return this.agent;
|
|
23
|
+
}
|
|
24
|
+
deleteAgent() {
|
|
25
|
+
this.agent = null;
|
|
26
|
+
}
|
|
27
|
+
setWorker(worker) {
|
|
28
|
+
this.workers.set(worker.workerId, worker);
|
|
29
|
+
}
|
|
30
|
+
getWorker(workerId) {
|
|
31
|
+
return this.workers.get(workerId);
|
|
32
|
+
}
|
|
33
|
+
deleteWorker(workerId) {
|
|
34
|
+
this.workers.delete(workerId);
|
|
35
|
+
}
|
|
36
|
+
listWorkerIds() {
|
|
37
|
+
return Array.from(this.workers.keys());
|
|
38
|
+
}
|
|
39
|
+
listWorkers() {
|
|
40
|
+
return Array.from(this.workers.values());
|
|
41
|
+
}
|
|
42
|
+
getListeningWorkerIds() {
|
|
43
|
+
const keys = [];
|
|
44
|
+
for (const [id, worker] of this.workers.entries()) {
|
|
45
|
+
if (worker.state === 'listening') {
|
|
46
|
+
keys.push(id);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return keys;
|
|
50
|
+
}
|
|
51
|
+
count() {
|
|
52
|
+
return {
|
|
53
|
+
agent: this.agent?.status === 'started' ? 1 : 0,
|
|
54
|
+
worker: this.listWorkerIds().length,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
// check agent and worker must both alive
|
|
58
|
+
// if exception appear 3 times, emit an exception event
|
|
59
|
+
startCheck() {
|
|
60
|
+
this.timer = setInterval(() => {
|
|
61
|
+
const count = this.count();
|
|
62
|
+
if (count.agent > 0 && count.worker > 0) {
|
|
63
|
+
this.exception = 0;
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
this.exception++;
|
|
67
|
+
if (this.exception >= 3) {
|
|
68
|
+
this.emit('exception', count);
|
|
69
|
+
clearInterval(this.timer);
|
|
70
|
+
}
|
|
71
|
+
}, 10000);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid29ya2VyX21hbmFnZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdXRpbHMvd29ya2VyX21hbmFnZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUUzQyxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDdkQsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBRW5ELGtFQUFrRTtBQUNsRSxzREFBc0Q7QUFDdEQsTUFBTSxPQUFPLGFBQWMsU0FBUSxZQUFZO0lBQzdDLEtBQUssQ0FBeUI7SUFDOUIsT0FBTyxHQUFHLElBQUksR0FBRyxFQUF5QixDQUFDO0lBQzNDLFNBQVMsR0FBRyxDQUFDLENBQUM7SUFDZCxLQUFLLENBQWlCO0lBRXRCO1FBQ0UsS0FBSyxFQUFFLENBQUM7UUFDUixJQUFJLENBQUMsS0FBSyxHQUFHLElBQUksQ0FBQztJQUNwQixDQUFDO0lBRUQsVUFBVTtRQUNSLE9BQU8sS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7SUFDekMsQ0FBQztJQUVELFFBQVEsQ0FBQyxLQUFzQjtRQUM3QixJQUFJLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQztJQUNyQixDQUFDO0lBRUQsUUFBUTtRQUNOLE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQztJQUNwQixDQUFDO0lBRUQsV0FBVztRQUNULElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDO0lBQ3BCLENBQUM7SUFFRCxTQUFTLENBQUMsTUFBcUI7UUFDN0IsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLFFBQVEsRUFBRSxNQUFNLENBQUMsQ0FBQztJQUM1QyxDQUFDO0lBRUQsU0FBUyxDQUFDLFFBQWdCO1FBQ3hCLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDcEMsQ0FBQztJQUVELFlBQVksQ0FBQyxRQUFnQjtRQUMzQixJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUNoQyxDQUFDO0lBRUQsYUFBYTtRQUNYLE9BQU8sS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7SUFDekMsQ0FBQztJQUVELFdBQVc7UUFDVCxPQUFPLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDO0lBQzNDLENBQUM7SUFFRCxxQkFBcUI7UUFDbkIsTUFBTSxJQUFJLEdBQUcsRUFBRSxDQUFDO1FBQ2hCLEtBQUssTUFBTSxDQUFDLEVBQUUsRUFBRSxNQUFNLENBQUMsSUFBSSxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUM7WUFDbEQsSUFBSSxNQUFNLENBQUMsS0FBSyxLQUFLLFdBQVcsRUFBRSxDQUFDO2dCQUNqQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQ2hCLENBQUM7UUFDSCxDQUFDO1FBQ0QsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQsS0FBSztRQUNILE9BQU87WUFDTCxLQUFLLEVBQUUsSUFBSSxDQUFDLEtBQUssRUFBRSxNQUFNLEtBQUssU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDL0MsTUFBTSxFQUFFLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQyxNQUFNO1NBQ3BDLENBQUM7SUFDSixDQUFDO0lBRUQseUNBQXlDO0lBQ3pDLHVEQUF1RDtJQUN2RCxVQUFVO1FBQ1IsSUFBSSxDQUFDLEtBQUssR0FBRyxXQUFXLENBQUMsR0FBRyxFQUFFO1lBQzVCLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztZQUMzQixJQUFJLEtBQUssQ0FBQyxLQUFLLEdBQUcsQ0FBQyxJQUFJLEtBQUssQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQ3hDLElBQUksQ0FBQyxTQUFTLEdBQUcsQ0FBQyxDQUFDO2dCQUNuQixPQUFPO1lBQ1QsQ0FBQztZQUNELElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztZQUNqQixJQUFJLElBQUksQ0FBQyxTQUFTLElBQUksQ0FBQyxFQUFFLENBQUM7Z0JBQ3hCLElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLEtBQUssQ0FBQyxDQUFDO2dCQUM5QixhQUFhLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQzVCLENBQUM7UUFDSCxDQUFDLEVBQUUsS0FBSyxDQUFDLENBQUM7SUFDWixDQUFDO0NBQ0YifQ==
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eggjs/cluster",
|
|
3
|
-
"version": "4.0.0-beta.
|
|
3
|
+
"version": "4.0.0-beta.21",
|
|
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.
|
|
48
|
+
"@eggjs/utils": "5.0.0-beta.21"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"address": "2",
|
|
@@ -55,15 +55,15 @@
|
|
|
55
55
|
"typescript": "^5.9.3",
|
|
56
56
|
"urllib": "^4.8.2",
|
|
57
57
|
"vitest": "4.0.0-beta.16",
|
|
58
|
-
"@eggjs/
|
|
59
|
-
"@eggjs/
|
|
60
|
-
"@eggjs/tsconfig": "3.1.0-beta.
|
|
58
|
+
"@eggjs/mock": "7.0.0-beta.21",
|
|
59
|
+
"@eggjs/supertest": "9.0.0-beta.21",
|
|
60
|
+
"@eggjs/tsconfig": "3.1.0-beta.21"
|
|
61
61
|
},
|
|
62
62
|
"engines": {
|
|
63
63
|
"node": ">=22.18.0"
|
|
64
64
|
},
|
|
65
65
|
"scripts": {
|
|
66
|
-
"build": "tsdown",
|
|
66
|
+
"build": "tsdown && rimraf dist && tsc -b --clean && tsc",
|
|
67
67
|
"lint": "oxlint",
|
|
68
68
|
"typecheck": "tsc --noEmit",
|
|
69
69
|
"test": "vitest run"
|
package/dist/agent-griHEaCW.js
DELETED
|
@@ -1,246 +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 workerThreads from "node:worker_threads";
|
|
6
|
-
import { fork } from "node:child_process";
|
|
7
|
-
import { sendmessage } from "sendmessage";
|
|
8
|
-
import { graceful } from "graceful-process";
|
|
9
|
-
|
|
10
|
-
//#region src/utils/mode/base/agent.ts
|
|
11
|
-
var BaseAgentWorker = class {
|
|
12
|
-
instance;
|
|
13
|
-
#instanceId;
|
|
14
|
-
#instanceStatus;
|
|
15
|
-
constructor(instance) {
|
|
16
|
-
this.instance = instance;
|
|
17
|
-
}
|
|
18
|
-
get id() {
|
|
19
|
-
return this.#instanceId;
|
|
20
|
-
}
|
|
21
|
-
set id(id) {
|
|
22
|
-
this.#instanceId = id;
|
|
23
|
-
}
|
|
24
|
-
get status() {
|
|
25
|
-
return this.#instanceStatus;
|
|
26
|
-
}
|
|
27
|
-
set status(status) {
|
|
28
|
-
this.#instanceStatus = status;
|
|
29
|
-
}
|
|
30
|
-
static send(_message) {
|
|
31
|
-
throw new Error("BaseAgentWorker should implement send.");
|
|
32
|
-
}
|
|
33
|
-
static kill() {
|
|
34
|
-
throw new Error("BaseAgentWorker should implement kill.");
|
|
35
|
-
}
|
|
36
|
-
static gracefulExit(_options) {
|
|
37
|
-
throw new Error("BaseAgentWorker should implement gracefulExit.");
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
var BaseAgentUtils = class extends EventEmitter {
|
|
41
|
-
options;
|
|
42
|
-
messenger;
|
|
43
|
-
log;
|
|
44
|
-
logger;
|
|
45
|
-
startTime = 0;
|
|
46
|
-
constructor(options, { log, logger, messenger }) {
|
|
47
|
-
super();
|
|
48
|
-
this.options = options;
|
|
49
|
-
this.log = log;
|
|
50
|
-
this.logger = logger;
|
|
51
|
-
this.messenger = messenger;
|
|
52
|
-
}
|
|
53
|
-
getAgentWorkerFile() {
|
|
54
|
-
let agentWorkerFile = path.join(getSrcDirname(), "agent_worker.js");
|
|
55
|
-
if (!existsSync(agentWorkerFile)) agentWorkerFile = path.join(getSrcDirname(), "agent_worker.ts");
|
|
56
|
-
return agentWorkerFile;
|
|
57
|
-
}
|
|
58
|
-
fork() {
|
|
59
|
-
throw new Error("BaseAgent should implement fork.");
|
|
60
|
-
}
|
|
61
|
-
clean() {
|
|
62
|
-
throw new Error("BaseAgent should implement clean.");
|
|
63
|
-
}
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
//#endregion
|
|
67
|
-
//#region src/error/ClusterAgentWorkerError.ts
|
|
68
|
-
var ClusterAgentWorkerError = class extends Error {
|
|
69
|
-
id;
|
|
70
|
-
/**
|
|
71
|
-
* pid in process mode
|
|
72
|
-
* tid in worker_threads mode
|
|
73
|
-
*/
|
|
74
|
-
workerId;
|
|
75
|
-
status;
|
|
76
|
-
constructor(id, workerId, status, error) {
|
|
77
|
-
const message = `Got agent worker error: ${error.message}`;
|
|
78
|
-
super(message, { cause: error });
|
|
79
|
-
this.name = this.constructor.name;
|
|
80
|
-
this.id = id;
|
|
81
|
-
this.workerId = workerId;
|
|
82
|
-
this.status = status;
|
|
83
|
-
Error.captureStackTrace(this, this.constructor);
|
|
84
|
-
}
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
//#endregion
|
|
88
|
-
//#region src/utils/mode/impl/process/agent.ts
|
|
89
|
-
var AgentProcessWorker = class extends BaseAgentWorker {
|
|
90
|
-
get workerId() {
|
|
91
|
-
return this.instance.pid;
|
|
92
|
-
}
|
|
93
|
-
send(message) {
|
|
94
|
-
sendmessage(this.instance, message);
|
|
95
|
-
}
|
|
96
|
-
static send(message) {
|
|
97
|
-
message.senderWorkerId = String(process.pid);
|
|
98
|
-
process.send(message);
|
|
99
|
-
}
|
|
100
|
-
static kill() {
|
|
101
|
-
process.exitCode = 1;
|
|
102
|
-
process.kill(process.pid);
|
|
103
|
-
}
|
|
104
|
-
static gracefulExit(options) {
|
|
105
|
-
graceful(options);
|
|
106
|
-
}
|
|
107
|
-
};
|
|
108
|
-
var AgentProcessUtils = class extends BaseAgentUtils {
|
|
109
|
-
#agentProcess;
|
|
110
|
-
#id = 0;
|
|
111
|
-
instance;
|
|
112
|
-
fork() {
|
|
113
|
-
this.startTime = Date.now();
|
|
114
|
-
const args = [JSON.stringify(this.options)];
|
|
115
|
-
const forkOptions = {};
|
|
116
|
-
if (process.platform === "win32") forkOptions.windowsHide = true;
|
|
117
|
-
const debugPort = process.env.EGG_AGENT_DEBUG_PORT ?? 5800;
|
|
118
|
-
if (this.options.isDebug) forkOptions.execArgv = process.execArgv.concat([`--inspect-port=${debugPort}`]);
|
|
119
|
-
const agentProcess = this.#agentProcess = fork(this.getAgentWorkerFile(), args, forkOptions);
|
|
120
|
-
const agentWorker = this.instance = new AgentProcessWorker(agentProcess);
|
|
121
|
-
agentWorker.status = "starting";
|
|
122
|
-
agentWorker.id = ++this.#id;
|
|
123
|
-
this.emit("agent_forked", agentWorker);
|
|
124
|
-
this.log("[master] agent_worker#%s:%s start with clusterPort:%s", agentWorker.id, agentWorker.workerId, this.options.clusterPort);
|
|
125
|
-
if (this.options.isDebug) this.messenger.send({
|
|
126
|
-
to: "parent",
|
|
127
|
-
from: "agent",
|
|
128
|
-
action: "debug",
|
|
129
|
-
data: {
|
|
130
|
-
debugPort,
|
|
131
|
-
pid: agentWorker.workerId,
|
|
132
|
-
workerId: agentWorker.workerId
|
|
133
|
-
}
|
|
134
|
-
});
|
|
135
|
-
agentProcess.on("message", (msg) => {
|
|
136
|
-
if (typeof msg === "string") msg = {
|
|
137
|
-
action: msg,
|
|
138
|
-
data: msg
|
|
139
|
-
};
|
|
140
|
-
msg.from = "agent";
|
|
141
|
-
this.messenger.send(msg);
|
|
142
|
-
});
|
|
143
|
-
agentProcess.on("error", (err) => {
|
|
144
|
-
err.name = "AgentWorkerError";
|
|
145
|
-
this.logger.error(new ClusterAgentWorkerError(agentWorker.id, agentWorker.workerId, agentWorker.status, err));
|
|
146
|
-
});
|
|
147
|
-
agentProcess.once("exit", (code, signal) => {
|
|
148
|
-
this.messenger.send({
|
|
149
|
-
action: "agent-exit",
|
|
150
|
-
data: {
|
|
151
|
-
code,
|
|
152
|
-
signal
|
|
153
|
-
},
|
|
154
|
-
to: "master",
|
|
155
|
-
from: "agent"
|
|
156
|
-
});
|
|
157
|
-
});
|
|
158
|
-
return this;
|
|
159
|
-
}
|
|
160
|
-
clean() {
|
|
161
|
-
this.#agentProcess.removeAllListeners();
|
|
162
|
-
}
|
|
163
|
-
async kill(timeout) {
|
|
164
|
-
if (this.#agentProcess) {
|
|
165
|
-
this.log("[master] kill agent worker with signal SIGTERM");
|
|
166
|
-
this.clean();
|
|
167
|
-
await terminate(this.#agentProcess, timeout);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
};
|
|
171
|
-
|
|
172
|
-
//#endregion
|
|
173
|
-
//#region src/utils/mode/impl/worker_threads/agent.ts
|
|
174
|
-
var AgentThreadWorker = class extends BaseAgentWorker {
|
|
175
|
-
get workerId() {
|
|
176
|
-
return this.instance.threadId;
|
|
177
|
-
}
|
|
178
|
-
send(message) {
|
|
179
|
-
this.instance.postMessage(message);
|
|
180
|
-
}
|
|
181
|
-
static send(message) {
|
|
182
|
-
message.senderWorkerId = String(workerThreads.threadId);
|
|
183
|
-
workerThreads.parentPort.postMessage(message);
|
|
184
|
-
}
|
|
185
|
-
static kill() {
|
|
186
|
-
process.exit(1);
|
|
187
|
-
}
|
|
188
|
-
static gracefulExit(options) {
|
|
189
|
-
const { beforeExit } = options;
|
|
190
|
-
process.on("exit", async (code) => {
|
|
191
|
-
if (typeof beforeExit === "function") await beforeExit();
|
|
192
|
-
process.exit(code);
|
|
193
|
-
});
|
|
194
|
-
}
|
|
195
|
-
};
|
|
196
|
-
var AgentThreadUtils = class extends BaseAgentUtils {
|
|
197
|
-
#worker;
|
|
198
|
-
#id = 0;
|
|
199
|
-
instance;
|
|
200
|
-
fork() {
|
|
201
|
-
this.startTime = Date.now();
|
|
202
|
-
const argv = [JSON.stringify(this.options)];
|
|
203
|
-
const agentPath = this.getAgentWorkerFile();
|
|
204
|
-
const worker = this.#worker = new workerThreads.Worker(agentPath, { argv });
|
|
205
|
-
const agentWorker = this.instance = new AgentThreadWorker(worker);
|
|
206
|
-
this.emit("agent_forked", agentWorker);
|
|
207
|
-
agentWorker.status = "starting";
|
|
208
|
-
agentWorker.id = ++this.#id;
|
|
209
|
-
this.log("[master] agent_worker#%s:%s start with worker_threads", agentWorker.id, agentWorker.workerId);
|
|
210
|
-
worker.on("message", (msg) => {
|
|
211
|
-
if (typeof msg === "string") msg = {
|
|
212
|
-
action: msg,
|
|
213
|
-
data: msg
|
|
214
|
-
};
|
|
215
|
-
msg.from = "agent";
|
|
216
|
-
this.messenger.send(msg);
|
|
217
|
-
});
|
|
218
|
-
worker.on("error", (err) => {
|
|
219
|
-
this.logger.error(new ClusterAgentWorkerError(agentWorker.id, agentWorker.workerId, agentWorker.status, err));
|
|
220
|
-
});
|
|
221
|
-
worker.once("exit", (code, signal) => {
|
|
222
|
-
this.messenger.send({
|
|
223
|
-
action: "agent-exit",
|
|
224
|
-
data: {
|
|
225
|
-
code,
|
|
226
|
-
signal
|
|
227
|
-
},
|
|
228
|
-
to: "master",
|
|
229
|
-
from: "agent"
|
|
230
|
-
});
|
|
231
|
-
});
|
|
232
|
-
}
|
|
233
|
-
clean() {
|
|
234
|
-
this.#worker.removeAllListeners();
|
|
235
|
-
}
|
|
236
|
-
async kill() {
|
|
237
|
-
if (this.#worker) {
|
|
238
|
-
this.log(`[master] kill agent worker#${this.#id} (worker_threads) by worker.terminate()`);
|
|
239
|
-
this.clean();
|
|
240
|
-
await this.#worker.terminate();
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
};
|
|
244
|
-
|
|
245
|
-
//#endregion
|
|
246
|
-
export { AgentProcessUtils, AgentProcessWorker, AgentThreadUtils, AgentThreadWorker, ClusterAgentWorkerError };
|