@abtnode/core 1.17.8-beta-20260108-224855-28496abb → 1.17.8-beta-20260111-112953-aed5ff39
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/api/team/access-key-manager.js +104 -0
- package/lib/api/team/invitation-manager.js +461 -0
- package/lib/api/team/notification-manager.js +189 -0
- package/lib/api/team/oauth-manager.js +60 -0
- package/lib/api/team/org-crud-manager.js +202 -0
- package/lib/api/team/org-manager.js +56 -0
- package/lib/api/team/org-member-manager.js +403 -0
- package/lib/api/team/org-query-manager.js +126 -0
- package/lib/api/team/org-resource-manager.js +186 -0
- package/lib/api/team/passport-manager.js +670 -0
- package/lib/api/team/rbac-manager.js +335 -0
- package/lib/api/team/session-manager.js +540 -0
- package/lib/api/team/store-manager.js +198 -0
- package/lib/api/team/tag-manager.js +230 -0
- package/lib/api/team/user-auth-manager.js +132 -0
- package/lib/api/team/user-manager.js +78 -0
- package/lib/api/team/user-query-manager.js +299 -0
- package/lib/api/team/user-social-manager.js +354 -0
- package/lib/api/team/user-update-manager.js +224 -0
- package/lib/api/team/verify-code-manager.js +161 -0
- package/lib/api/team.js +439 -3287
- package/lib/blocklet/manager/disk/auth-manager.js +68 -0
- package/lib/blocklet/manager/disk/backup-manager.js +288 -0
- package/lib/blocklet/manager/disk/cleanup-manager.js +157 -0
- package/lib/blocklet/manager/disk/component-manager.js +83 -0
- package/lib/blocklet/manager/disk/config-manager.js +191 -0
- package/lib/blocklet/manager/disk/controller-manager.js +64 -0
- package/lib/blocklet/manager/disk/delete-reset-manager.js +328 -0
- package/lib/blocklet/manager/disk/download-manager.js +96 -0
- package/lib/blocklet/manager/disk/env-config-manager.js +311 -0
- package/lib/blocklet/manager/disk/federated-manager.js +651 -0
- package/lib/blocklet/manager/disk/hook-manager.js +124 -0
- package/lib/blocklet/manager/disk/install-component-manager.js +95 -0
- package/lib/blocklet/manager/disk/install-core-manager.js +448 -0
- package/lib/blocklet/manager/disk/install-download-manager.js +313 -0
- package/lib/blocklet/manager/disk/install-manager.js +36 -0
- package/lib/blocklet/manager/disk/install-upgrade-manager.js +340 -0
- package/lib/blocklet/manager/disk/job-manager.js +467 -0
- package/lib/blocklet/manager/disk/lifecycle-manager.js +26 -0
- package/lib/blocklet/manager/disk/notification-manager.js +343 -0
- package/lib/blocklet/manager/disk/query-manager.js +562 -0
- package/lib/blocklet/manager/disk/settings-manager.js +507 -0
- package/lib/blocklet/manager/disk/start-manager.js +611 -0
- package/lib/blocklet/manager/disk/stop-restart-manager.js +292 -0
- package/lib/blocklet/manager/disk/update-manager.js +153 -0
- package/lib/blocklet/manager/disk.js +669 -5796
- package/lib/blocklet/manager/helper/blue-green-start-blocklet.js +5 -0
- package/lib/blocklet/manager/lock.js +18 -0
- package/lib/event/index.js +28 -24
- package/lib/router/helper.js +5 -1
- package/lib/util/blocklet/app-utils.js +192 -0
- package/lib/util/blocklet/blocklet-loader.js +258 -0
- package/lib/util/blocklet/config-manager.js +232 -0
- package/lib/util/blocklet/did-document.js +240 -0
- package/lib/util/blocklet/environment.js +555 -0
- package/lib/util/blocklet/health-check.js +449 -0
- package/lib/util/blocklet/install-utils.js +365 -0
- package/lib/util/blocklet/logo.js +57 -0
- package/lib/util/blocklet/meta-utils.js +269 -0
- package/lib/util/blocklet/port-manager.js +141 -0
- package/lib/util/blocklet/process-manager.js +504 -0
- package/lib/util/blocklet/runtime-info.js +105 -0
- package/lib/util/blocklet/validation.js +418 -0
- package/lib/util/blocklet.js +98 -3066
- package/lib/util/wallet-app-notification.js +40 -0
- package/package.json +22 -22
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
/* eslint-disable no-await-in-loop */
|
|
2
|
+
/**
|
|
3
|
+
* Health Check Module
|
|
4
|
+
*
|
|
5
|
+
* Functions for checking blocklet process health status
|
|
6
|
+
* Extracted from blocklet.js for better modularity
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const logger = require('@abtnode/logger')('@abtnode/core:util:blocklet:health-check');
|
|
10
|
+
const sleep = require('@abtnode/util/lib/sleep');
|
|
11
|
+
const ensureEndpointHealthy = require('@abtnode/util/lib/ensure-endpoint-healthy');
|
|
12
|
+
const promiseSpawn = require('@abtnode/util/lib/promise-spawn');
|
|
13
|
+
const { forEachBlocklet, hasStartEngine } = require('@blocklet/meta/lib/util');
|
|
14
|
+
const { getBlockletEngine } = require('@blocklet/meta/lib/engine');
|
|
15
|
+
|
|
16
|
+
const {
|
|
17
|
+
BlockletStatus,
|
|
18
|
+
BlockletGroup,
|
|
19
|
+
BLOCKLET_MODES,
|
|
20
|
+
BLOCKLET_INTERFACE_TYPE_WEB,
|
|
21
|
+
BLOCKLET_INTERFACE_TYPE_DOCKER,
|
|
22
|
+
} = require('@blocklet/constant');
|
|
23
|
+
|
|
24
|
+
const { getProcessInfo, shouldSkipComponent } = require('./process-manager');
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Get actual listening port from Docker container or process
|
|
28
|
+
* @param {string} processId - PM2 process ID
|
|
29
|
+
* @param {object} blocklet - Blocklet object with meta and env
|
|
30
|
+
* @returns {Promise<number|null>} Actual port number or null if not found
|
|
31
|
+
*/
|
|
32
|
+
const getActualListeningPort = async (processId, blocklet) => {
|
|
33
|
+
try {
|
|
34
|
+
const info = await getProcessInfo(processId, { timeout: 3_000 });
|
|
35
|
+
const dockerName = info.pm2_env?.env?.dockerName;
|
|
36
|
+
|
|
37
|
+
if (dockerName) {
|
|
38
|
+
// For Docker containers, get actual port from docker inspect
|
|
39
|
+
try {
|
|
40
|
+
// Get port mapping from docker inspect
|
|
41
|
+
const inspectCmd = `docker inspect --format='{{range $p, $conf := .NetworkSettings.Ports}}{{$p}} {{end}}' ${dockerName}`;
|
|
42
|
+
const portMappings = await promiseSpawn(inspectCmd, { mute: true });
|
|
43
|
+
|
|
44
|
+
if (portMappings) {
|
|
45
|
+
const ports = portMappings.trim().split(/\s+/).filter(Boolean);
|
|
46
|
+
for (const portMapping of ports) {
|
|
47
|
+
const port = parseInt(portMapping.split('/')[0], 10);
|
|
48
|
+
if (port && !Number.isNaN(port)) {
|
|
49
|
+
try {
|
|
50
|
+
const portCmd = `docker port ${dockerName} ${portMapping}`;
|
|
51
|
+
const hostPortOutput = await promiseSpawn(portCmd, { mute: true });
|
|
52
|
+
const match = hostPortOutput.match(/:(\d+)$/);
|
|
53
|
+
if (match) {
|
|
54
|
+
const actualPort = parseInt(match[1], 10);
|
|
55
|
+
if (actualPort && !Number.isNaN(actualPort)) {
|
|
56
|
+
logger.info('Got actual Docker port from container', {
|
|
57
|
+
processId,
|
|
58
|
+
dockerName,
|
|
59
|
+
containerPort: port,
|
|
60
|
+
hostPort: actualPort,
|
|
61
|
+
});
|
|
62
|
+
return actualPort;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
} catch (err) {
|
|
66
|
+
logger.debug('Failed to get port from docker port command', { error: err.message });
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Fallback: try to get from NetworkSettings.Ports directly
|
|
73
|
+
const inspectPortsCmd = `docker inspect --format='{{json .NetworkSettings.Ports}}' ${dockerName}`;
|
|
74
|
+
const portsJson = await promiseSpawn(inspectPortsCmd, { mute: true });
|
|
75
|
+
if (portsJson) {
|
|
76
|
+
const portsObj = JSON.parse(portsJson);
|
|
77
|
+
// Find the primary port (usually BLOCKLET_PORT)
|
|
78
|
+
const webInterface = (blocklet?.meta?.interfaces || []).find(
|
|
79
|
+
(x) => x.type === BLOCKLET_INTERFACE_TYPE_WEB || x.type === BLOCKLET_INTERFACE_TYPE_DOCKER
|
|
80
|
+
);
|
|
81
|
+
const expectedContainerPort = webInterface?.containerPort || webInterface?.port;
|
|
82
|
+
|
|
83
|
+
if (expectedContainerPort) {
|
|
84
|
+
const portKey = `${expectedContainerPort}/tcp`;
|
|
85
|
+
if (portsObj[portKey] && portsObj[portKey][0]) {
|
|
86
|
+
const hostPort = parseInt(portsObj[portKey][0].HostPort, 10);
|
|
87
|
+
if (hostPort && !Number.isNaN(hostPort)) {
|
|
88
|
+
logger.info('Got actual Docker port from NetworkSettings', {
|
|
89
|
+
processId,
|
|
90
|
+
dockerName,
|
|
91
|
+
containerPort: expectedContainerPort,
|
|
92
|
+
hostPort,
|
|
93
|
+
});
|
|
94
|
+
return hostPort;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
} catch (error) {
|
|
100
|
+
logger.debug('Failed to get Docker port mapping', { error: error.message, processId, dockerName });
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return null;
|
|
105
|
+
} catch (error) {
|
|
106
|
+
logger.debug('Failed to get actual listening port', { error: error.message, processId });
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Get healthy check timeout configuration
|
|
113
|
+
* @param {object} blocklet - Blocklet object
|
|
114
|
+
* @param {object} options - Options
|
|
115
|
+
* @param {boolean} options.checkHealthImmediately - Whether to check immediately
|
|
116
|
+
* @param {Array} options.componentDids - Component DIDs to filter
|
|
117
|
+
* @returns {{ startTimeout: number, minConsecutiveTime: number }}
|
|
118
|
+
*/
|
|
119
|
+
const getHealthyCheckTimeout = (blocklet, { checkHealthImmediately, componentDids } = {}) => {
|
|
120
|
+
let minConsecutiveTime = 3000;
|
|
121
|
+
if (process.env.NODE_ENV === 'test' && process.env.ABT_NODE_TEST_MIN_CONSECUTIVE_TIME !== undefined) {
|
|
122
|
+
minConsecutiveTime = +process.env.ABT_NODE_TEST_MIN_CONSECUTIVE_TIME;
|
|
123
|
+
} else if (checkHealthImmediately) {
|
|
124
|
+
minConsecutiveTime = 3000;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (process.env.BLOCKLET_START_TIMEOUT) {
|
|
128
|
+
return {
|
|
129
|
+
startTimeout: +process.env.BLOCKLET_START_TIMEOUT * 1000,
|
|
130
|
+
minConsecutiveTime,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
if (blocklet.mode === BLOCKLET_MODES.DEVELOPMENT) {
|
|
134
|
+
return {
|
|
135
|
+
startTimeout: 3600 * 1000,
|
|
136
|
+
minConsecutiveTime: 3000,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const children = componentDids?.length
|
|
141
|
+
? blocklet.children.filter((child) => componentDids.includes(child.meta.did))
|
|
142
|
+
: blocklet.children;
|
|
143
|
+
|
|
144
|
+
// Let's wait for at least 1 minute for the blocklet to go live
|
|
145
|
+
let startTimeout =
|
|
146
|
+
Math.max(blocklet.meta?.timeout?.start || 60, ...(children || []).map((child) => child.meta?.timeout?.start || 0)) *
|
|
147
|
+
1000;
|
|
148
|
+
|
|
149
|
+
if (process.env.NODE_ENV === 'test') {
|
|
150
|
+
startTimeout = 10 * 1000;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return {
|
|
154
|
+
startTimeout,
|
|
155
|
+
minConsecutiveTime,
|
|
156
|
+
};
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Internal function to check process health
|
|
161
|
+
* @param {object} blocklet - Blocklet component
|
|
162
|
+
* @param {object} options - Check options
|
|
163
|
+
* @param {number} options.minConsecutiveTime - Minimum consecutive healthy time
|
|
164
|
+
* @param {number} options.timeout - Timeout in ms
|
|
165
|
+
* @param {boolean} options.logToTerminal - Whether to log to terminal
|
|
166
|
+
* @param {boolean} options.isGreen - Whether checking green deployment
|
|
167
|
+
* @param {string} options.appDid - App DID for logging
|
|
168
|
+
* @param {Function} findInterfacePortByName - Function to find port by interface name
|
|
169
|
+
* @returns {Promise<void>}
|
|
170
|
+
*/
|
|
171
|
+
const _checkProcessHealthy = async (
|
|
172
|
+
blocklet,
|
|
173
|
+
{ minConsecutiveTime, timeout, logToTerminal, isGreen = false, appDid, findInterfacePortByName }
|
|
174
|
+
) => {
|
|
175
|
+
const { meta, ports, greenPorts, env } = blocklet;
|
|
176
|
+
const { name } = meta;
|
|
177
|
+
const processId = isGreen ? `${env.processId}-green` : env.processId;
|
|
178
|
+
|
|
179
|
+
const webInterface = (meta.interfaces || []).find((x) => x.type === BLOCKLET_INTERFACE_TYPE_WEB);
|
|
180
|
+
const dockerInterface = (meta.interfaces || []).find((x) => x.type === BLOCKLET_INTERFACE_TYPE_DOCKER);
|
|
181
|
+
|
|
182
|
+
if (!webInterface && !dockerInterface) {
|
|
183
|
+
// TODO: how do we check healthy for service interfaces
|
|
184
|
+
throw new Error(`Blocklet ${name} does not have any web interface`);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
try {
|
|
188
|
+
// ensure pm2 status is 'online'
|
|
189
|
+
const getStatus = async () => {
|
|
190
|
+
try {
|
|
191
|
+
const info = await getProcessInfo(processId, { timeout: 3_000 });
|
|
192
|
+
return { status: info.pm2_env.status, envPort: info.pm2_env.BLOCKLET_PORT };
|
|
193
|
+
} catch (err) {
|
|
194
|
+
logger.error('blocklet checkStart error', { appDid, error: err, processId, name });
|
|
195
|
+
return { status: '', envPort: null };
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
// eslint-disable-next-line prefer-const
|
|
200
|
+
let { status, envPort } = await getStatus();
|
|
201
|
+
|
|
202
|
+
for (let i = 0; i < 20 && status !== 'online'; i++) {
|
|
203
|
+
const t = process.env.NODE_ENV !== 'test' ? 500 : 30;
|
|
204
|
+
await sleep(t);
|
|
205
|
+
({ status, envPort } = await getStatus());
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (status !== 'online') {
|
|
209
|
+
throw new Error('process not start within 10s');
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Get actual listening port from Docker container or process
|
|
213
|
+
// This avoids using stale port after port refresh
|
|
214
|
+
const actualPort = await getActualListeningPort(processId, blocklet);
|
|
215
|
+
|
|
216
|
+
// Port priority: actual port > pm2 env port > database port
|
|
217
|
+
const port =
|
|
218
|
+
actualPort ||
|
|
219
|
+
envPort ||
|
|
220
|
+
findInterfacePortByName({ meta, ports: isGreen ? greenPorts : ports }, (webInterface || dockerInterface).name);
|
|
221
|
+
|
|
222
|
+
if (logToTerminal) {
|
|
223
|
+
logger.info(
|
|
224
|
+
// eslint-disable-next-line no-nested-ternary
|
|
225
|
+
`Checking endpoint healthy for ${meta.title}, port: ${port}${actualPort ? ' (actual)' : envPort ? ' (from pm2 env)' : ' (from db)'}, minConsecutiveTime: ${
|
|
226
|
+
minConsecutiveTime / 1000
|
|
227
|
+
}s, timeout: ${timeout / 1000}s`
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (
|
|
232
|
+
actualPort &&
|
|
233
|
+
actualPort !== envPort &&
|
|
234
|
+
actualPort !==
|
|
235
|
+
(isGreen
|
|
236
|
+
? greenPorts?.[webInterface?.port || dockerInterface?.port]
|
|
237
|
+
: ports?.[webInterface?.port || dockerInterface?.port])
|
|
238
|
+
) {
|
|
239
|
+
logger.info('Port mismatch detected, using actual port for health check', {
|
|
240
|
+
processId,
|
|
241
|
+
appDid,
|
|
242
|
+
actualPort,
|
|
243
|
+
envPort,
|
|
244
|
+
dbPort: isGreen
|
|
245
|
+
? greenPorts?.[webInterface?.port || dockerInterface?.port]
|
|
246
|
+
: ports?.[webInterface?.port || dockerInterface?.port],
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
try {
|
|
251
|
+
await ensureEndpointHealthy({
|
|
252
|
+
port,
|
|
253
|
+
protocol: webInterface ? 'http' : 'tcp',
|
|
254
|
+
minConsecutiveTime,
|
|
255
|
+
timeout,
|
|
256
|
+
doConsecutiveCheck: blocklet.mode !== BLOCKLET_MODES.DEVELOPMENT,
|
|
257
|
+
waitTCP: !webInterface,
|
|
258
|
+
shouldAbort: async () => {
|
|
259
|
+
// Check if pm2 process exists and is online
|
|
260
|
+
try {
|
|
261
|
+
const info = await getProcessInfo(processId, { timeout: 3_000 });
|
|
262
|
+
const currentStatus = info.pm2_env.status;
|
|
263
|
+
if (currentStatus !== 'online') {
|
|
264
|
+
throw new Error(`pm2 process ${processId} status is ${currentStatus}, not online`);
|
|
265
|
+
}
|
|
266
|
+
} catch (err) {
|
|
267
|
+
// If process doesn't exist or has error, abort immediately
|
|
268
|
+
logger.error('pm2 process check failed in shouldAbort', { appDid, error: err, processId, name });
|
|
269
|
+
const isProcessNotExist =
|
|
270
|
+
err.message &&
|
|
271
|
+
(err.message.includes('not found') ||
|
|
272
|
+
err.message.includes('does not exist') ||
|
|
273
|
+
err.message.includes('not running'));
|
|
274
|
+
if (isProcessNotExist) {
|
|
275
|
+
throw new Error(`pm2 process ${processId} (${name}) died or does not exist: ${err.message}`);
|
|
276
|
+
}
|
|
277
|
+
throw new Error(`pm2 process ${processId} (${name}) check failed: ${err.message}`);
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
});
|
|
281
|
+
} catch (error) {
|
|
282
|
+
const isProcessDead =
|
|
283
|
+
error.message &&
|
|
284
|
+
(error.message.includes('pm2 process') ||
|
|
285
|
+
error.message.includes('died') ||
|
|
286
|
+
error.message.includes('does not exist'));
|
|
287
|
+
if (isProcessDead) {
|
|
288
|
+
logger.error('blocklet process died during health check', {
|
|
289
|
+
appDid,
|
|
290
|
+
processId,
|
|
291
|
+
name,
|
|
292
|
+
port,
|
|
293
|
+
error: error.message,
|
|
294
|
+
});
|
|
295
|
+
throw error;
|
|
296
|
+
}
|
|
297
|
+
logger.error('ensure endpoint healthy failed', {
|
|
298
|
+
appDid,
|
|
299
|
+
port,
|
|
300
|
+
minConsecutiveTime,
|
|
301
|
+
timeout,
|
|
302
|
+
error: error.message,
|
|
303
|
+
});
|
|
304
|
+
throw error;
|
|
305
|
+
}
|
|
306
|
+
} catch (error) {
|
|
307
|
+
logger.error('start blocklet failed', { processId, name });
|
|
308
|
+
throw error;
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Check if all blocklet components are healthy
|
|
314
|
+
* @param {object} blocklet - Root blocklet
|
|
315
|
+
* @param {object} options - Options
|
|
316
|
+
* @param {number} options.minConsecutiveTime - Minimum consecutive healthy time
|
|
317
|
+
* @param {number} options.timeout - Timeout in ms
|
|
318
|
+
* @param {Array} options.componentDids - Component DIDs to check
|
|
319
|
+
* @param {Function} options.setBlockletRunning - Callback when blocklet becomes running
|
|
320
|
+
* @param {boolean} options.isGreen - Whether checking green deployment
|
|
321
|
+
* @param {string} options.appDid - App DID for logging
|
|
322
|
+
* @param {Function} options.findInterfacePortByName - Function to find port by interface name
|
|
323
|
+
* @returns {Promise<void>}
|
|
324
|
+
*/
|
|
325
|
+
const checkBlockletProcessHealthy = async (
|
|
326
|
+
blocklet,
|
|
327
|
+
{
|
|
328
|
+
minConsecutiveTime,
|
|
329
|
+
timeout,
|
|
330
|
+
componentDids,
|
|
331
|
+
setBlockletRunning,
|
|
332
|
+
isGreen = false,
|
|
333
|
+
appDid,
|
|
334
|
+
findInterfacePortByName,
|
|
335
|
+
} = {}
|
|
336
|
+
) => {
|
|
337
|
+
await forEachBlocklet(
|
|
338
|
+
blocklet,
|
|
339
|
+
async (b) => {
|
|
340
|
+
if (b.meta.group === BlockletGroup.gateway) {
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// components that relies on another engine component should not be checked
|
|
345
|
+
const engine = getBlockletEngine(b.meta);
|
|
346
|
+
if (engine.interpreter === 'blocklet') {
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
if (!hasStartEngine(b.meta)) {
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
if (shouldSkipComponent(b.meta.did, componentDids)) {
|
|
355
|
+
logger.info('skip check component healthy', { processId: b.env.processId });
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
const logToTerminal = [blocklet.mode, b.mode].includes(BLOCKLET_MODES.DEVELOPMENT);
|
|
360
|
+
|
|
361
|
+
const startedAt = Date.now();
|
|
362
|
+
|
|
363
|
+
await _checkProcessHealthy(b, {
|
|
364
|
+
minConsecutiveTime,
|
|
365
|
+
timeout,
|
|
366
|
+
logToTerminal,
|
|
367
|
+
isGreen,
|
|
368
|
+
appDid,
|
|
369
|
+
findInterfacePortByName,
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
logger.info('done check component healthy', { processId: b.env.processId, time: Date.now() - startedAt });
|
|
373
|
+
|
|
374
|
+
if (setBlockletRunning) {
|
|
375
|
+
try {
|
|
376
|
+
await setBlockletRunning(b.meta.did);
|
|
377
|
+
} catch (error) {
|
|
378
|
+
logger.error(`Failed to set blocklet as running for DID: ${b.meta.name || b.meta.did}`, { error });
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
},
|
|
382
|
+
{ parallel: true }
|
|
383
|
+
);
|
|
384
|
+
};
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Check if a blocklet should have health check
|
|
388
|
+
* @param {object} blocklet - Blocklet component
|
|
389
|
+
* @returns {boolean}
|
|
390
|
+
*/
|
|
391
|
+
const shouldCheckHealthy = (blocklet) => {
|
|
392
|
+
if (blocklet.meta.group === BlockletGroup.gateway) {
|
|
393
|
+
return false;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// components that relies on another engine component should not be checked
|
|
397
|
+
const engine = getBlockletEngine(blocklet.meta);
|
|
398
|
+
if (engine.interpreter === 'blocklet') {
|
|
399
|
+
return false;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
return hasStartEngine(blocklet.meta);
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* Check if blocklet port is healthy
|
|
407
|
+
* @param {object} blocklet - Blocklet object
|
|
408
|
+
* @param {object} options - Options
|
|
409
|
+
* @param {number} options.minConsecutiveTime - Minimum consecutive healthy time (default 3000ms)
|
|
410
|
+
* @param {number} options.timeout - Timeout in ms (default 10s)
|
|
411
|
+
* @returns {Promise<void>}
|
|
412
|
+
*/
|
|
413
|
+
const isBlockletPortHealthy = async (blocklet, { minConsecutiveTime = 3000, timeout = 10 * 1000 } = {}) => {
|
|
414
|
+
if (!blocklet) {
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
const { environments } = blocklet;
|
|
418
|
+
const webInterface = (blocklet.meta?.interfaces || []).find((x) => x.type === BLOCKLET_INTERFACE_TYPE_WEB);
|
|
419
|
+
const dockerInterface = (blocklet.meta?.interfaces || []).find((x) => x.type === BLOCKLET_INTERFACE_TYPE_DOCKER);
|
|
420
|
+
const key = webInterface?.port || dockerInterface?.port || 'BLOCKLET_PORT';
|
|
421
|
+
|
|
422
|
+
let port = blocklet.greenStatus === BlockletStatus.running ? blocklet.greenPorts?.[key] : blocklet.ports?.[key];
|
|
423
|
+
|
|
424
|
+
if (!port) {
|
|
425
|
+
const keyPort = webInterface?.port || dockerInterface?.port;
|
|
426
|
+
port = environments?.find((e) => e.key === keyPort)?.value;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
if (!port) {
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
await ensureEndpointHealthy({
|
|
434
|
+
port,
|
|
435
|
+
protocol: webInterface ? 'http' : 'tcp',
|
|
436
|
+
minConsecutiveTime,
|
|
437
|
+
timeout,
|
|
438
|
+
doConsecutiveCheck: false,
|
|
439
|
+
});
|
|
440
|
+
};
|
|
441
|
+
|
|
442
|
+
module.exports = {
|
|
443
|
+
getActualListeningPort,
|
|
444
|
+
getHealthyCheckTimeout,
|
|
445
|
+
_checkProcessHealthy,
|
|
446
|
+
checkBlockletProcessHealthy,
|
|
447
|
+
shouldCheckHealthy,
|
|
448
|
+
isBlockletPortHealthy,
|
|
449
|
+
};
|