alemonjs 2.1.0-alpha.43 → 2.1.0-alpha.45
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/lib/adapter.js +22 -106
- package/package.json +1 -1
package/lib/adapter.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { fork } from 'child_process';
|
|
2
2
|
import { createRequire } from 'module';
|
|
3
|
-
import { createInterface } from 'readline';
|
|
4
3
|
|
|
5
4
|
const require = createRequire(import.meta.url);
|
|
6
5
|
/**
|
|
@@ -10,59 +9,6 @@ const require = createRequire(import.meta.url);
|
|
|
10
9
|
* @param env 环境变量对象
|
|
11
10
|
* @param logger 日志对象(需实现 info/warn/error)
|
|
12
11
|
*/
|
|
13
|
-
let currentChild;
|
|
14
|
-
let cleanupRegistered = false;
|
|
15
|
-
let shuttingDown = false; // 标记是否正在整体退出,避免触发重启
|
|
16
|
-
function terminateChild(reason) {
|
|
17
|
-
if (currentChild && !currentChild.killed) {
|
|
18
|
-
try {
|
|
19
|
-
logger?.debug?.(`即将终止平台连接子进程 pid=${currentChild.pid}${reason ? ' reason=' + reason : ''}`);
|
|
20
|
-
// 先尝试发送一个 shutdown 指令(如果对端支持)
|
|
21
|
-
try {
|
|
22
|
-
currentChild.send?.(JSON.stringify({ type: 'shutdown' }));
|
|
23
|
-
}
|
|
24
|
-
catch { /* ignore */ }
|
|
25
|
-
currentChild.removeAllListeners();
|
|
26
|
-
currentChild.kill('SIGTERM');
|
|
27
|
-
// 兜底强杀
|
|
28
|
-
setTimeout(() => {
|
|
29
|
-
if (currentChild && !currentChild.killed) {
|
|
30
|
-
try {
|
|
31
|
-
currentChild.kill('SIGKILL');
|
|
32
|
-
}
|
|
33
|
-
catch { /* ignore */ }
|
|
34
|
-
}
|
|
35
|
-
}, 3000).unref?.();
|
|
36
|
-
}
|
|
37
|
-
catch (e) {
|
|
38
|
-
logger?.warn?.('终止子进程失败', e);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
currentChild = undefined;
|
|
42
|
-
}
|
|
43
|
-
function registerProcessCleanup() {
|
|
44
|
-
if (cleanupRegistered) {
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
cleanupRegistered = true;
|
|
48
|
-
const signals = ['SIGINT', 'SIGTERM', 'SIGQUIT'];
|
|
49
|
-
const handle = (sig) => {
|
|
50
|
-
shuttingDown = true;
|
|
51
|
-
terminateChild(`parent ${sig}`);
|
|
52
|
-
};
|
|
53
|
-
signals.forEach(s => process.once(s, handle));
|
|
54
|
-
process.once('beforeExit', () => handle('beforeExit'));
|
|
55
|
-
process.once('exit', () => handle('exit'));
|
|
56
|
-
// 如果父进程与其父断开(例如被主控杀掉),也尝试清理
|
|
57
|
-
process.on('disconnect', () => {
|
|
58
|
-
shuttingDown = true;
|
|
59
|
-
terminateChild('parent disconnect');
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
function stopAdapter() {
|
|
63
|
-
shuttingDown = true;
|
|
64
|
-
terminateChild('manual stop');
|
|
65
|
-
}
|
|
66
12
|
function startAdapterWithFallback() {
|
|
67
13
|
let modulePath = '';
|
|
68
14
|
try {
|
|
@@ -80,51 +26,52 @@ function startAdapterWithFallback() {
|
|
|
80
26
|
}
|
|
81
27
|
let restarted = false;
|
|
82
28
|
let ready = false;
|
|
29
|
+
let child;
|
|
83
30
|
const restart = () => {
|
|
84
31
|
if (restarted || imported) {
|
|
85
32
|
return;
|
|
86
33
|
}
|
|
87
34
|
restarted = true;
|
|
88
|
-
|
|
35
|
+
if (child) {
|
|
36
|
+
child.removeAllListeners();
|
|
37
|
+
try {
|
|
38
|
+
child.kill();
|
|
39
|
+
}
|
|
40
|
+
catch { }
|
|
41
|
+
}
|
|
89
42
|
setTimeout(() => {
|
|
90
43
|
startByFork();
|
|
91
44
|
}, 3000);
|
|
92
45
|
};
|
|
93
46
|
try {
|
|
94
|
-
|
|
95
|
-
registerProcessCleanup();
|
|
47
|
+
child = fork(modulePath);
|
|
96
48
|
// 超时
|
|
97
49
|
const checkTimeout = async () => {
|
|
98
50
|
if (!ready && !imported) {
|
|
99
51
|
logger?.warn?.('平台连接未及时响应(未发送 ready 消息),降级为 import 加载, 请升级对应的平台连接包以提高进程稳定性');
|
|
100
52
|
try {
|
|
101
|
-
|
|
53
|
+
child?.kill();
|
|
102
54
|
}
|
|
103
55
|
catch { }
|
|
104
56
|
await startByImport();
|
|
105
57
|
}
|
|
106
58
|
};
|
|
107
59
|
const timer = setTimeout(() => void checkTimeout(), 2000);
|
|
108
|
-
|
|
60
|
+
child.on('exit', (code, signal) => {
|
|
109
61
|
clearTimeout(timer);
|
|
110
|
-
if (shuttingDown) {
|
|
111
|
-
logger?.debug?.('父进程正在关闭,忽略子进程退出重启逻辑');
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
62
|
if (!imported) {
|
|
115
63
|
logger?.warn?.(`平台连接子进程已退出,code=${code}, signal=${signal},3秒后自动重启`);
|
|
116
64
|
restart();
|
|
117
65
|
}
|
|
118
66
|
});
|
|
119
|
-
|
|
67
|
+
child.on('message', msg => {
|
|
120
68
|
try {
|
|
121
69
|
const data = typeof msg === 'string' ? JSON.parse(msg) : msg;
|
|
122
70
|
if (data?.type === 'ready') {
|
|
123
71
|
ready = true;
|
|
124
72
|
clearTimeout(timer);
|
|
125
73
|
logger?.debug?.('平台连接已就绪(子进程 fork 模式)');
|
|
126
|
-
|
|
127
|
-
currentChild?.send(JSON.stringify({ type: 'start' }));
|
|
74
|
+
child?.send?.({ type: 'start' });
|
|
128
75
|
}
|
|
129
76
|
}
|
|
130
77
|
catch (err) {
|
|
@@ -162,45 +109,14 @@ function startAdapterWithFallback() {
|
|
|
162
109
|
};
|
|
163
110
|
startByFork();
|
|
164
111
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
const data = typeof msg === 'string' ? JSON.parse(msg) : msg;
|
|
170
|
-
if (data?.type === 'shutdown') {
|
|
171
|
-
shuttingDown = true;
|
|
172
|
-
stopAdapter();
|
|
173
|
-
// 给父进程一个确认
|
|
174
|
-
try {
|
|
175
|
-
process.send?.(JSON.stringify({ type: 'shutdown-ack' }));
|
|
176
|
-
}
|
|
177
|
-
catch {
|
|
178
|
-
// ignore
|
|
179
|
-
}
|
|
180
|
-
// 适当延迟确保子进程杀干净
|
|
181
|
-
setTimeout(() => process.exit(0), 100);
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
catch { /* ignore parse errors */ }
|
|
112
|
+
['SIGINT', 'SIGTERM', 'SIGQUIT', 'disconnect'].forEach(sig => {
|
|
113
|
+
process?.on?.(sig, () => {
|
|
114
|
+
logger?.info?.(`[${sig}] 收到信号,正在关闭...`);
|
|
115
|
+
setImmediate(() => process.exit(0));
|
|
185
116
|
});
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
const rl = createInterface({ input: process.stdin, crlfDelay: Infinity });
|
|
191
|
-
rl.on('line', line => {
|
|
192
|
-
const cmd = line.trim().toLowerCase();
|
|
193
|
-
if (cmd === 'shutdown' || cmd === 'quit' || cmd === 'exit') {
|
|
194
|
-
shuttingDown = true;
|
|
195
|
-
stopAdapter();
|
|
196
|
-
rl.close();
|
|
197
|
-
setTimeout(() => process.exit(0), 50);
|
|
198
|
-
}
|
|
199
|
-
});
|
|
200
|
-
// 不阻止进程退出
|
|
201
|
-
rl.on('close', () => { });
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
catch { /* ignore */ }
|
|
117
|
+
});
|
|
118
|
+
process?.on?.('exit', (code) => {
|
|
119
|
+
logger?.info?.(`[exit] 进程退出,code=${code}`);
|
|
120
|
+
});
|
|
205
121
|
|
|
206
|
-
export { startAdapterWithFallback
|
|
122
|
+
export { startAdapterWithFallback };
|