alemonjs 2.1.89 → 2.1.90

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.
@@ -17,16 +17,274 @@ import { setClientChild, forwardFromClient } from './ipc-bridge.js';
17
17
  const initRequire = () => { };
18
18
  initRequire.resolve = () => '';
19
19
  const require$1 = module$1?.createRequire?.(import.meta.url) ?? initRequire;
20
- function startModuleAdapter() {
20
+ const createInitialState = () => ({
21
+ phase: 'idle',
22
+ protocolVersion: 'legacy',
23
+ transportMode: 'unknown',
24
+ restartCount: 0,
25
+ consecutiveFailures: 0,
26
+ legacyReadyMode: false,
27
+ bootTimings: {},
28
+ lastError: null
29
+ });
30
+ let moduleManager = null;
31
+ let moduleState = createInitialState();
32
+ let moduleProcessConfig = null;
33
+ let moduleProcessPath = '';
34
+ const isDebugEnabled = () => process.env.NODE_ENV === 'development';
35
+ const debugLog = (message, data = {}) => {
36
+ if (!isDebugEnabled()) {
37
+ return;
38
+ }
39
+ logger.debug?.({
40
+ message,
41
+ data
42
+ });
43
+ };
44
+ const normalizeErrorMessage = (error) => {
45
+ if (error instanceof Error) {
46
+ return error.message;
47
+ }
48
+ return typeof error === 'string' ? error : 'Unknown process adapter error';
49
+ };
50
+ const clearTimer = (timer) => {
51
+ if (timer) {
52
+ clearTimeout(timer);
53
+ }
54
+ };
55
+ const clearManagerTimers = (manager) => {
56
+ clearTimer(manager?.controlTimer);
57
+ clearTimer(manager?.transportTimer);
58
+ clearTimer(manager?.appTimer);
59
+ clearTimer(manager?.legacyTransportTimer);
60
+ if (manager) {
61
+ manager.controlTimer = undefined;
62
+ manager.transportTimer = undefined;
63
+ manager.appTimer = undefined;
64
+ manager.legacyTransportTimer = undefined;
65
+ }
66
+ };
67
+ const buildConfig = () => {
21
68
  const values = getConfigValue();
22
69
  const pro = values?.process ?? {};
23
- let modulePath = '';
24
- const CONFIG = {
25
- RESTART_DELAY: pro?.restart_delay ?? 3000,
26
- FORK_TIMEOUT: pro?.fork_timeout ?? 6000
70
+ return {
71
+ restartDelay: Number(pro?.restart_delay ?? 3000),
72
+ controlReadyTimeout: Number(pro?.control_ready_timeout ?? 10000),
73
+ transportReadyTimeout: Number(pro?.transport_ready_timeout ?? 15000),
74
+ appReadyTimeout: Number(pro?.app_ready_timeout ?? 30000),
75
+ maxRestartDelay: Number(pro?.max_restart_delay ?? 30000),
76
+ legacyTransportGraceMs: Number(pro?.legacy_transport_grace_ms ?? 50)
77
+ };
78
+ };
79
+ const resetBootState = () => {
80
+ moduleState = {
81
+ ...moduleState,
82
+ phase: 'booting',
83
+ protocolVersion: 'legacy',
84
+ transportMode: 'unknown',
85
+ legacyReadyMode: false,
86
+ startedAt: Date.now(),
87
+ lastReadyAt: undefined,
88
+ lastTransportReadyAt: undefined,
89
+ lastAppReadyAt: undefined,
90
+ bootTimings: {},
91
+ lastError: null
92
+ };
93
+ };
94
+ const updateTransportBinding = (transportMode) => {
95
+ if (transportMode === 'ipc' && moduleManager?.child) {
96
+ setClientChild(moduleManager.child);
97
+ }
98
+ else {
99
+ setClientChild(null);
100
+ }
101
+ };
102
+ const markFailure = (error) => {
103
+ moduleState = {
104
+ ...moduleState,
105
+ phase: 'failed',
106
+ lastError: error ? normalizeErrorMessage(error) : moduleState.lastError,
107
+ consecutiveFailures: moduleState.consecutiveFailures + 1
108
+ };
109
+ };
110
+ const markTransportReady = (transport, legacyReadyMode = false) => {
111
+ const now = Date.now();
112
+ if (!moduleManager) {
113
+ return;
114
+ }
115
+ moduleManager.transportReady = true;
116
+ clearTimer(moduleManager.transportTimer);
117
+ clearTimer(moduleManager.legacyTransportTimer);
118
+ moduleManager.transportTimer = undefined;
119
+ moduleManager.legacyTransportTimer = undefined;
120
+ moduleState = {
121
+ ...moduleState,
122
+ phase: moduleState.lastAppReadyAt ? 'app_ready' : 'transport_ready',
123
+ transportMode: transport,
124
+ lastTransportReadyAt: now,
125
+ legacyReadyMode,
126
+ consecutiveFailures: 0,
127
+ bootTimings: {
128
+ ...moduleState.bootTimings,
129
+ readyToTransportReadyMs: moduleState.lastReadyAt ? now - moduleState.lastReadyAt : undefined,
130
+ transportReadyToAppReadyMs: moduleState.lastAppReadyAt ? moduleState.lastAppReadyAt - now : moduleState.bootTimings.transportReadyToAppReadyMs
131
+ }
132
+ };
133
+ updateTransportBinding(transport);
134
+ if (legacyReadyMode) {
135
+ debugLog('module adapter fallback to legacy transport ready');
136
+ }
137
+ };
138
+ const scheduleRestart = (reason) => {
139
+ if (!moduleProcessConfig || !moduleProcessPath) {
140
+ return;
141
+ }
142
+ const baseDelay = moduleProcessConfig.restartDelay;
143
+ const delay = Math.min(baseDelay * 2 ** Math.max(moduleState.consecutiveFailures - 1, 0), moduleProcessConfig.maxRestartDelay);
144
+ moduleState = {
145
+ ...moduleState,
146
+ restartCount: moduleState.restartCount + 1
147
+ };
148
+ debugLog('schedule module adapter restart', { reason, delay });
149
+ setTimeout(() => {
150
+ startModuleAdapter();
151
+ }, delay);
152
+ };
153
+ const cleanupManager = (manager) => {
154
+ clearManagerTimers(manager);
155
+ if (manager?.child) {
156
+ manager.child.removeAllListeners();
157
+ }
158
+ setClientChild(null);
159
+ if (moduleManager === manager) {
160
+ moduleManager = null;
161
+ }
162
+ };
163
+ const handleControlReady = (manager, message) => {
164
+ const protocolVersion = message.protocolVersion === 'v2' ? 'v2' : 'legacy';
165
+ const now = Date.now();
166
+ manager.protocolVersion = protocolVersion;
167
+ clearTimer(manager.controlTimer);
168
+ manager.controlTimer = undefined;
169
+ moduleState = {
170
+ ...moduleState,
171
+ phase: 'control_ready',
172
+ protocolVersion,
173
+ legacyReadyMode: protocolVersion === 'legacy',
174
+ lastReadyAt: now,
175
+ bootTimings: {
176
+ ...moduleState.bootTimings,
177
+ forkToReadyMs: moduleState.startedAt ? now - moduleState.startedAt : undefined
178
+ }
179
+ };
180
+ manager.child?.send?.({ type: 'start' });
181
+ if (protocolVersion === 'v2') {
182
+ manager.transportTimer = setTimeout(() => {
183
+ logger?.warn?.({
184
+ code: ResultCode.Fail,
185
+ message: '模块加载进程未在规定时间内建立通讯层,正在重启',
186
+ data: null
187
+ });
188
+ manager.isKilling = true;
189
+ markFailure('transport_ready_timeout');
190
+ try {
191
+ manager.child?.kill();
192
+ }
193
+ catch {
194
+ cleanupManager(manager);
195
+ scheduleRestart('transport_ready_timeout');
196
+ }
197
+ }, moduleProcessConfig?.transportReadyTimeout ?? 15000);
198
+ manager.appTimer = setTimeout(() => {
199
+ logger?.warn?.({
200
+ code: ResultCode.Warn,
201
+ message: '模块加载进程业务初始化较慢,尚未收到 app_ready',
202
+ data: null
203
+ });
204
+ }, moduleProcessConfig?.appReadyTimeout ?? 30000);
205
+ }
206
+ else {
207
+ const legacyTransportMode = process.env.__ALEMON_DIRECT_SOCK ? 'direct' : 'ipc';
208
+ manager.legacyTransportTimer = setTimeout(() => {
209
+ if (!manager.transportReady) {
210
+ markTransportReady(legacyTransportMode, true);
211
+ }
212
+ }, moduleProcessConfig?.legacyTransportGraceMs ?? 50);
213
+ }
214
+ };
215
+ const handleMessage = (manager, message) => {
216
+ const data = typeof message === 'string' ? JSON.parse(message) : message;
217
+ if (data?.type === 'ready') {
218
+ handleControlReady(manager, data);
219
+ return;
220
+ }
221
+ if (data?.type === 'transport_ready') {
222
+ markTransportReady(data.transport ?? 'unknown');
223
+ return;
224
+ }
225
+ if (data?.type === 'app_ready') {
226
+ const now = Date.now();
227
+ manager.appReady = true;
228
+ clearTimer(manager.appTimer);
229
+ manager.appTimer = undefined;
230
+ moduleState = {
231
+ ...moduleState,
232
+ phase: 'app_ready',
233
+ lastAppReadyAt: now,
234
+ bootTimings: {
235
+ ...moduleState.bootTimings,
236
+ transportReadyToAppReadyMs: moduleState.lastTransportReadyAt ? now - moduleState.lastTransportReadyAt : moduleState.bootTimings.transportReadyToAppReadyMs
237
+ }
238
+ };
239
+ return;
240
+ }
241
+ if (data?.type === 'boot_error') {
242
+ moduleState = {
243
+ ...moduleState,
244
+ lastError: normalizeErrorMessage(data.error?.message ?? data.error)
245
+ };
246
+ logger?.warn?.({
247
+ code: ResultCode.Fail,
248
+ message: `模块加载进程启动阶段失败: ${String(data.stage ?? 'unknown')}`,
249
+ data: data.error ?? null
250
+ });
251
+ return;
252
+ }
253
+ if (data?.type === 'ipc:data') {
254
+ forwardFromClient(data.data);
255
+ }
256
+ };
257
+ const getModuleAdapterState = () => ({
258
+ ...moduleState,
259
+ bootTimings: { ...moduleState.bootTimings }
260
+ });
261
+ function restartModuleAdapter() {
262
+ if (!moduleManager?.child) {
263
+ startModuleAdapter();
264
+ return;
265
+ }
266
+ if (moduleManager.restartRequested) {
267
+ return;
268
+ }
269
+ moduleManager.restartRequested = true;
270
+ moduleManager.isKilling = true;
271
+ moduleState = {
272
+ ...moduleState,
273
+ phase: 'stopping'
27
274
  };
275
+ clearManagerTimers(moduleManager);
28
276
  try {
29
- modulePath = require$1.resolve('../../client.js');
277
+ moduleManager.child.kill();
278
+ }
279
+ catch {
280
+ cleanupManager(moduleManager);
281
+ scheduleRestart('manual_restart');
282
+ }
283
+ }
284
+ function startModuleAdapter() {
285
+ moduleProcessConfig = buildConfig();
286
+ try {
287
+ moduleProcessPath = require$1.resolve('../../client.js');
30
288
  }
31
289
  catch (error) {
32
290
  logger?.warn?.({
@@ -34,112 +292,91 @@ function startModuleAdapter() {
34
292
  message: '模块加载进程启动失败',
35
293
  data: error
36
294
  });
295
+ markFailure(error);
37
296
  return;
38
297
  }
39
- const startByFork = () => {
40
- const manager = {
41
- restarted: false,
42
- ready: false
43
- };
44
- const clearTimer = () => {
45
- if (manager.timer) {
46
- clearTimeout(manager.timer);
47
- manager.timer = undefined;
48
- }
49
- };
50
- const cleanup = () => {
51
- clearTimer();
52
- if (manager.child) {
53
- manager.child.removeAllListeners();
54
- }
55
- setClientChild(null);
56
- };
57
- const restart = () => {
58
- if (manager.restarted) {
298
+ if (moduleManager?.child && moduleManager.child.exitCode === null && !moduleManager.child.killed) {
299
+ return;
300
+ }
301
+ resetBootState();
302
+ const manager = {
303
+ isKilling: false,
304
+ restartRequested: false,
305
+ transportReady: false,
306
+ appReady: false,
307
+ protocolVersion: 'legacy'
308
+ };
309
+ moduleManager = manager;
310
+ manager.controlTimer = setTimeout(() => {
311
+ logger?.error?.({
312
+ code: ResultCode.Fail,
313
+ message: '模块加载进程未及时发送 ready,正在重启',
314
+ data: null
315
+ });
316
+ manager.isKilling = true;
317
+ markFailure('control_ready_timeout');
318
+ try {
319
+ manager.child?.kill();
320
+ }
321
+ catch {
322
+ cleanupManager(manager);
323
+ scheduleRestart('control_ready_timeout');
324
+ }
325
+ }, moduleProcessConfig.controlReadyTimeout);
326
+ try {
327
+ manager.child = childProcess.fork(moduleProcessPath, [], {
328
+ execArgv: process.execArgv,
329
+ env: { ...process.env, __ALEMON_IPC: '1' },
330
+ serialization: 'advanced'
331
+ });
332
+ manager.child.on('exit', (code, signal) => {
333
+ cleanupManager(manager);
334
+ if (manager.isKilling || manager.restartRequested) {
335
+ scheduleRestart(manager.restartRequested ? 'manual_restart' : 'timeout_or_kill');
59
336
  return;
60
337
  }
61
- manager.restarted = true;
62
- cleanup();
63
- setTimeout(() => {
64
- startByFork();
65
- }, CONFIG.RESTART_DELAY);
66
- };
67
- const checkTimeout = () => {
68
- if (!manager.ready) {
69
- logger?.error?.({
70
- code: ResultCode.Fail,
71
- message: '模块加载未及时响应(未发送 ready 消息)',
72
- data: null
73
- });
74
- try {
75
- manager.child?.kill();
76
- }
77
- catch {
78
- }
79
- }
80
- };
81
- try {
82
- manager.child = childProcess.fork(modulePath, [], {
83
- execArgv: process.execArgv,
84
- env: { ...process.env, __ALEMON_IPC: '1' },
85
- serialization: 'advanced'
86
- });
87
- manager.timer = setTimeout(checkTimeout, CONFIG.FORK_TIMEOUT);
88
- manager.child.on('exit', (code, signal) => {
89
- cleanup();
90
- logger?.warn?.({
91
- code: ResultCode.Fail,
92
- message: `模块加载子进程已退出,code=${code}, signal=${signal},${CONFIG.RESTART_DELAY / 1000}秒后自动重启`,
93
- data: null
94
- });
95
- restart();
96
- });
97
- manager.child.on('message', (message) => {
98
- try {
99
- const data = typeof message === 'string' ? JSON.parse(message) : message;
100
- if (data?.type === 'ready') {
101
- manager.ready = true;
102
- clearTimer();
103
- setClientChild(manager.child);
104
- logger?.debug?.({
105
- code: ResultCode.Ok,
106
- message: '模块加载已就绪(IPC)',
107
- data: null
108
- });
109
- manager.child?.send?.({ type: 'start' });
110
- }
111
- else if (data?.type === 'ipc:data') {
112
- forwardFromClient(data.data);
113
- }
114
- }
115
- catch (error) {
116
- logger?.error?.({
117
- code: ResultCode.Fail,
118
- message: '模块加载进程通信数据格式错误',
119
- data: error
120
- });
121
- }
338
+ logger?.warn?.({
339
+ code: ResultCode.Fail,
340
+ message: `模块加载子进程已退出,code=${code}, signal=${signal},稍后自动重启`,
341
+ data: null
122
342
  });
123
- manager.child.on('error', error => {
343
+ markFailure(`exit:${code ?? 'null'}:${signal ?? 'null'}`);
344
+ scheduleRestart('unexpected_exit');
345
+ });
346
+ manager.child.on('message', message => {
347
+ try {
348
+ handleMessage(manager, message);
349
+ }
350
+ catch (error) {
124
351
  logger?.error?.({
125
352
  code: ResultCode.Fail,
126
- message: '模块加载子进程发生错误',
353
+ message: '模块加载进程通信数据格式错误',
127
354
  data: error
128
355
  });
129
- });
130
- }
131
- catch (error) {
132
- logger?.warn?.({
356
+ }
357
+ });
358
+ manager.child.on('error', error => {
359
+ logger?.error?.({
133
360
  code: ResultCode.Fail,
134
- message: 'fork 启动模块加载失败',
361
+ message: '模块加载子进程发生错误',
135
362
  data: error
136
363
  });
137
- setTimeout(() => {
138
- startByFork();
139
- }, CONFIG.RESTART_DELAY);
140
- }
141
- };
142
- startByFork();
364
+ moduleState = {
365
+ ...moduleState,
366
+ lastError: normalizeErrorMessage(error)
367
+ };
368
+ });
369
+ }
370
+ catch (error) {
371
+ cleanupManager(manager);
372
+ logger?.warn?.({
373
+ code: ResultCode.Fail,
374
+ message: 'fork 启动模块加载失败',
375
+ data: error
376
+ });
377
+ markFailure(error);
378
+ scheduleRestart('fork_error');
379
+ }
143
380
  }
144
381
 
145
- export { startModuleAdapter };
382
+ export { getModuleAdapterState, restartModuleAdapter, startModuleAdapter };
@@ -1 +1,4 @@
1
+ import type { ProcessAdapterState } from './types';
2
+ export declare const getPlatformAdapterState: () => ProcessAdapterState;
3
+ export declare function restartPlatformAdapter(): void;
1
4
  export declare function startPlatformAdapterWithFallback(): Promise<void>;