@abtnode/core 1.17.8-beta-20260109-075740-5f484e08 → 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/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,611 @@
|
|
|
1
|
+
/* eslint-disable no-await-in-loop */
|
|
2
|
+
const uniq = require('lodash/uniq');
|
|
3
|
+
const logger = require('@abtnode/logger')('@abtnode/core:blocklet:manager:start');
|
|
4
|
+
const pAll = require('p-all');
|
|
5
|
+
const { BlockletEvents, BlockletInternalEvents, BlockletStatus, BlockletGroup } = require('@blocklet/constant');
|
|
6
|
+
const {
|
|
7
|
+
forEachBlocklet,
|
|
8
|
+
hasStartEngine,
|
|
9
|
+
hasRunnableComponent,
|
|
10
|
+
getDisplayName,
|
|
11
|
+
isExternalBlocklet,
|
|
12
|
+
getComponentMissingConfigs,
|
|
13
|
+
} = require('@blocklet/meta/lib/util');
|
|
14
|
+
const { getRequiredComponentsLayers } = require('@blocklet/meta/lib/get-required-components-layers');
|
|
15
|
+
const { getBlockletEngine } = require('@blocklet/meta/lib/engine');
|
|
16
|
+
const { getComponentsInternalInfo } = require('@blocklet/meta/lib/blocklet');
|
|
17
|
+
|
|
18
|
+
const states = require('../../../states');
|
|
19
|
+
const launcher = require('../../../util/launcher');
|
|
20
|
+
const hooks = require('../../hooks');
|
|
21
|
+
const { startLock } = require('../lock');
|
|
22
|
+
const {
|
|
23
|
+
startBlockletProcess,
|
|
24
|
+
getRuntimeEnvironments,
|
|
25
|
+
validateBlocklet,
|
|
26
|
+
validateBlockletChainInfo,
|
|
27
|
+
ensureAppPortsNotOccupied,
|
|
28
|
+
getHealthyCheckTimeout,
|
|
29
|
+
shouldSkipComponent,
|
|
30
|
+
getComponentNamesWithVersion,
|
|
31
|
+
getHookArgs,
|
|
32
|
+
} = require('../../../util/blocklet');
|
|
33
|
+
const checkNeedRunDocker = require('../../../util/docker/check-need-run-docker');
|
|
34
|
+
const { dockerExec } = require('../../../util/docker/docker-exec');
|
|
35
|
+
const { dockerExecChown } = require('../../../util/docker/docker-exec-chown');
|
|
36
|
+
const checkDockerRunHistory = require('../../../util/docker/check-docker-run-history');
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Start required components by dependency order
|
|
40
|
+
*/
|
|
41
|
+
async function startRequiredComponents(
|
|
42
|
+
manager,
|
|
43
|
+
{
|
|
44
|
+
componentDids,
|
|
45
|
+
inputComponentDids,
|
|
46
|
+
blocklet,
|
|
47
|
+
throwOnError,
|
|
48
|
+
checkHealthImmediately,
|
|
49
|
+
e2eMode,
|
|
50
|
+
context,
|
|
51
|
+
atomic,
|
|
52
|
+
onStarted,
|
|
53
|
+
onError,
|
|
54
|
+
}
|
|
55
|
+
) {
|
|
56
|
+
if (!blocklet.children) {
|
|
57
|
+
return componentDids;
|
|
58
|
+
}
|
|
59
|
+
const targetDid = !inputComponentDids?.length ? componentDids?.[0] : inputComponentDids[0];
|
|
60
|
+
|
|
61
|
+
const canStartStatus = {
|
|
62
|
+
[BlockletStatus.installed]: true,
|
|
63
|
+
[BlockletStatus.error]: true,
|
|
64
|
+
[BlockletStatus.stopped]: true,
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const requiredDidsLayers = getRequiredComponentsLayers({
|
|
68
|
+
targetDid,
|
|
69
|
+
children: blocklet.children,
|
|
70
|
+
filter: (child) => atomic || canStartStatus[child.status],
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
logger.info('start required components', {
|
|
74
|
+
did: blocklet.meta.did,
|
|
75
|
+
targetDid,
|
|
76
|
+
componentDids,
|
|
77
|
+
inputComponentDids,
|
|
78
|
+
checkHealthImmediately,
|
|
79
|
+
requiredDidsLayers,
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
if (requiredDidsLayers.length) {
|
|
83
|
+
// start by dependency
|
|
84
|
+
for (const dids of requiredDidsLayers) {
|
|
85
|
+
if (atomic) {
|
|
86
|
+
await _start(
|
|
87
|
+
manager,
|
|
88
|
+
{ blocklet, throwOnError, checkHealthImmediately, e2eMode, componentDids: dids, onStarted, onError },
|
|
89
|
+
context
|
|
90
|
+
);
|
|
91
|
+
} else {
|
|
92
|
+
const tasks = dids.map(
|
|
93
|
+
(x) => () =>
|
|
94
|
+
_start(
|
|
95
|
+
manager,
|
|
96
|
+
{ blocklet, throwOnError, checkHealthImmediately, e2eMode, componentDids: [x], onStarted, onError },
|
|
97
|
+
context
|
|
98
|
+
)
|
|
99
|
+
);
|
|
100
|
+
await pAll(tasks, { concurrency: 4 }).catch((err) => {
|
|
101
|
+
throw new Error(err.errors ? err.errors.join(', ') : err);
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// remove the components that have just been started
|
|
108
|
+
const startedDids = new Set(requiredDidsLayers.flat());
|
|
109
|
+
return componentDids.filter((x) => !startedDids.has(x));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Start blocklet
|
|
114
|
+
*/
|
|
115
|
+
async function start(
|
|
116
|
+
manager,
|
|
117
|
+
{
|
|
118
|
+
did,
|
|
119
|
+
throwOnError,
|
|
120
|
+
checkHealthImmediately = false,
|
|
121
|
+
e2eMode = false,
|
|
122
|
+
componentDids: inputComponentDids,
|
|
123
|
+
atomic,
|
|
124
|
+
operator,
|
|
125
|
+
},
|
|
126
|
+
context
|
|
127
|
+
) {
|
|
128
|
+
const lockName = `${did}-start`;
|
|
129
|
+
const shouldLock = inputComponentDids?.length === 0;
|
|
130
|
+
|
|
131
|
+
if (shouldLock) {
|
|
132
|
+
await startLock.acquire(lockName);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
try {
|
|
136
|
+
const blocklet = await manager.ensureBlocklet(did, { e2eMode });
|
|
137
|
+
const baseComponentDids = uniq(
|
|
138
|
+
inputComponentDids?.length ? inputComponentDids : blocklet.children.map((x) => x.meta.did)
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
try {
|
|
142
|
+
await manager.deleteProcess({ did, componentDids: baseComponentDids, isGreen: true });
|
|
143
|
+
} catch (error) {
|
|
144
|
+
logger.warn('Failed to delete process; this warning can be safely ignored.', { error });
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
await manager.checkControllerStatus(blocklet, 'start');
|
|
148
|
+
|
|
149
|
+
// 优先启动资源型组件
|
|
150
|
+
const componentDids = [];
|
|
151
|
+
const nonEntryComponentIds = [];
|
|
152
|
+
for (const b of blocklet.children) {
|
|
153
|
+
if (!b?.meta?.did) {
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
if (!baseComponentDids.includes(b.meta.did)) {
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
if (!hasStartEngine(b.meta)) {
|
|
160
|
+
nonEntryComponentIds.push(b.meta.did);
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
const engine = getBlockletEngine(b.meta);
|
|
164
|
+
if (engine.interpreter === 'blocklet') {
|
|
165
|
+
nonEntryComponentIds.push(b.meta.did);
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
componentDids.push(b.meta.did);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
await manager.checkControllerStatus(blocklet, 'start');
|
|
172
|
+
|
|
173
|
+
if (nonEntryComponentIds.length) {
|
|
174
|
+
await states.blocklet.setBlockletStatus(did, BlockletStatus.running, {
|
|
175
|
+
componentDids: nonEntryComponentIds,
|
|
176
|
+
operator,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
// sync component config before at first to ensure resource component config is ready
|
|
180
|
+
const serverSk = (await states.node.read()).sk;
|
|
181
|
+
await Promise.all(
|
|
182
|
+
componentDids.map((componentDid) =>
|
|
183
|
+
manager.configSynchronizer.syncComponentConfig(componentDid, blocklet.meta.did, { serverSk })
|
|
184
|
+
)
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
// 如果只有 nonEntryComponent,没有 entry component,直接触发 started 事件并返回
|
|
188
|
+
if (componentDids.length === 0) {
|
|
189
|
+
const finalBlocklet = await manager.getBlocklet(did);
|
|
190
|
+
await manager.configSynchronizer.throttledSyncAppConfig(finalBlocklet);
|
|
191
|
+
const componentsInfo = getComponentsInternalInfo(finalBlocklet);
|
|
192
|
+
manager.emit(BlockletInternalEvents.componentUpdated, {
|
|
193
|
+
appDid: blocklet.appDid,
|
|
194
|
+
components: componentsInfo,
|
|
195
|
+
});
|
|
196
|
+
manager.emit(BlockletInternalEvents.componentStarted, {
|
|
197
|
+
appDid: blocklet.appDid,
|
|
198
|
+
components: nonEntryComponentIds.map((x) => ({ did: x })),
|
|
199
|
+
});
|
|
200
|
+
manager.emit(BlockletEvents.statusChange, finalBlocklet);
|
|
201
|
+
manager.emit(BlockletEvents.started, { ...finalBlocklet, componentDids: nonEntryComponentIds });
|
|
202
|
+
launcher.notifyBlockletStarted(finalBlocklet);
|
|
203
|
+
|
|
204
|
+
// 根据情况更新 route table
|
|
205
|
+
if (!['true', '1'].includes(process.env.ABT_NODE_DISABLE_BLUE_GREEN)) {
|
|
206
|
+
manager.emit(BlockletEvents.blueOrGreenStarted, {
|
|
207
|
+
blocklet: finalBlocklet,
|
|
208
|
+
componentDids: inputComponentDids,
|
|
209
|
+
context,
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return finalBlocklet;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const doc1 = await states.blocklet.setBlockletStatus(did, BlockletStatus.starting, {
|
|
217
|
+
componentDids,
|
|
218
|
+
operator,
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
manager.emit(BlockletEvents.statusChange, doc1);
|
|
222
|
+
const startedBlockletDids = [];
|
|
223
|
+
const errorBlockletDids = [];
|
|
224
|
+
const parentBlockletId = blocklet.id;
|
|
225
|
+
|
|
226
|
+
// Helper function to update child status immediately and emit events
|
|
227
|
+
const updateChildStatusImmediately = async (componentDid, status) => {
|
|
228
|
+
if (!states.blockletChild || !parentBlockletId) {
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
try {
|
|
233
|
+
await states.blockletChild.updateChildStatus(parentBlockletId, componentDid, {
|
|
234
|
+
status,
|
|
235
|
+
operator,
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
// Get updated blocklet to emit events
|
|
239
|
+
const updatedBlocklet = await manager.getBlocklet(did);
|
|
240
|
+
const componentsInfo = getComponentsInternalInfo(updatedBlocklet);
|
|
241
|
+
|
|
242
|
+
manager.emit(BlockletInternalEvents.componentUpdated, {
|
|
243
|
+
appDid: blocklet.appDid,
|
|
244
|
+
components: componentsInfo.filter((c) => c.did === componentDid),
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
if (status === BlockletStatus.running) {
|
|
248
|
+
manager.emit(BlockletInternalEvents.componentStarted, {
|
|
249
|
+
appDid: blocklet.appDid,
|
|
250
|
+
components: [{ did: componentDid }],
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
manager.emit(BlockletEvents.statusChange, updatedBlocklet);
|
|
255
|
+
} catch (err) {
|
|
256
|
+
logger.error('Failed to update child status immediately', {
|
|
257
|
+
componentDid,
|
|
258
|
+
status,
|
|
259
|
+
error: err.message,
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
const notStartedComponentDids = await startRequiredComponents(manager, {
|
|
265
|
+
componentDids,
|
|
266
|
+
inputComponentDids,
|
|
267
|
+
blocklet,
|
|
268
|
+
throwOnError,
|
|
269
|
+
checkHealthImmediately,
|
|
270
|
+
e2eMode,
|
|
271
|
+
context,
|
|
272
|
+
atomic,
|
|
273
|
+
onStarted: async (subDid) => {
|
|
274
|
+
startedBlockletDids.push({ did: subDid });
|
|
275
|
+
await updateChildStatusImmediately(subDid, BlockletStatus.running);
|
|
276
|
+
},
|
|
277
|
+
onError: async (subDid, error) => {
|
|
278
|
+
errorBlockletDids.push({ did: subDid, error });
|
|
279
|
+
await updateChildStatusImmediately(subDid, BlockletStatus.error);
|
|
280
|
+
},
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
const tasks = notStartedComponentDids.map(
|
|
284
|
+
(componentDid) => () =>
|
|
285
|
+
_start(
|
|
286
|
+
manager,
|
|
287
|
+
{
|
|
288
|
+
blocklet,
|
|
289
|
+
throwOnError,
|
|
290
|
+
checkHealthImmediately,
|
|
291
|
+
e2eMode,
|
|
292
|
+
componentDids: [componentDid],
|
|
293
|
+
operator,
|
|
294
|
+
onStarted: async (subDid) => {
|
|
295
|
+
startedBlockletDids.push({ did: subDid });
|
|
296
|
+
await updateChildStatusImmediately(subDid, BlockletStatus.running);
|
|
297
|
+
},
|
|
298
|
+
onError: async (subDid, error) => {
|
|
299
|
+
errorBlockletDids.push({ did: subDid, error });
|
|
300
|
+
await updateChildStatusImmediately(subDid, BlockletStatus.error);
|
|
301
|
+
},
|
|
302
|
+
},
|
|
303
|
+
context
|
|
304
|
+
)
|
|
305
|
+
);
|
|
306
|
+
|
|
307
|
+
await pAll(tasks, { concurrency: 6 });
|
|
308
|
+
|
|
309
|
+
// Sync parent blocklet uptime status once after all components are processed
|
|
310
|
+
await states.blocklet.syncUptimeStatus(parentBlockletId);
|
|
311
|
+
|
|
312
|
+
const nextBlocklet = await manager.ensureBlocklet(did, { e2eMode });
|
|
313
|
+
let errorDescription = '';
|
|
314
|
+
let resultBlocklet = nextBlocklet;
|
|
315
|
+
|
|
316
|
+
// Status updates are now done immediately in callbacks, so we only need to handle final events and cleanup
|
|
317
|
+
if (startedBlockletDids.length) {
|
|
318
|
+
const finalBlocklet = await manager.getBlocklet(did);
|
|
319
|
+
resultBlocklet = finalBlocklet;
|
|
320
|
+
|
|
321
|
+
// Sync app config after all components started
|
|
322
|
+
await manager.configSynchronizer.throttledSyncAppConfig(finalBlocklet, { wait: 200 });
|
|
323
|
+
const componentsInfo = getComponentsInternalInfo(finalBlocklet);
|
|
324
|
+
manager.emit(BlockletInternalEvents.componentUpdated, {
|
|
325
|
+
appDid: blocklet.appDid,
|
|
326
|
+
components: componentsInfo,
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
const allStartedComponentDids = uniq([
|
|
330
|
+
...(componentDids || []),
|
|
331
|
+
...nonEntryComponentIds,
|
|
332
|
+
...startedBlockletDids.map((x) => x.did),
|
|
333
|
+
]);
|
|
334
|
+
manager.emit(BlockletInternalEvents.componentStarted, {
|
|
335
|
+
appDid: blocklet.appDid,
|
|
336
|
+
components: allStartedComponentDids.map((x) => ({ did: x })),
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
manager.emit(BlockletEvents.statusChange, finalBlocklet);
|
|
340
|
+
manager.emit(BlockletEvents.started, { ...finalBlocklet, componentDids: allStartedComponentDids });
|
|
341
|
+
|
|
342
|
+
launcher.notifyBlockletStarted(finalBlocklet);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
if (errorBlockletDids.length) {
|
|
346
|
+
const error = errorBlockletDids[0];
|
|
347
|
+
for (const item of errorBlockletDids) {
|
|
348
|
+
logger.error('Failed to start blocklet', {
|
|
349
|
+
error: item.error,
|
|
350
|
+
title: nextBlocklet.meta.title,
|
|
351
|
+
name: getComponentNamesWithVersion(nextBlocklet, [item.did]),
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
errorDescription = `${getComponentNamesWithVersion(
|
|
356
|
+
nextBlocklet,
|
|
357
|
+
errorBlockletDids.map((x) => x.did)
|
|
358
|
+
)} start failed for ${getDisplayName(nextBlocklet)}: ${errorBlockletDids.map((x) => x.error.message).join('. ')}`;
|
|
359
|
+
manager._createNotification(did, {
|
|
360
|
+
title: `${errorBlockletDids.length > 1 ? `${errorBlockletDids.length} components` : 'Component'} failed to start for ${getDisplayName(nextBlocklet)}`,
|
|
361
|
+
description: errorDescription,
|
|
362
|
+
entityType: 'blocklet',
|
|
363
|
+
entityId: did,
|
|
364
|
+
severity: 'error',
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
await manager.deleteProcess({
|
|
368
|
+
did,
|
|
369
|
+
componentDids: errorBlockletDids.map((x) => x.did),
|
|
370
|
+
shouldUpdateBlockletStatus: false,
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
const finalBlocklet = await manager.getBlocklet(did);
|
|
374
|
+
resultBlocklet = finalBlocklet;
|
|
375
|
+
manager.emit(BlockletEvents.startFailed, {
|
|
376
|
+
...finalBlocklet,
|
|
377
|
+
componentDids: errorBlockletDids.map((x) => x.did),
|
|
378
|
+
error: { message: error.message },
|
|
379
|
+
});
|
|
380
|
+
manager.emit(BlockletEvents.statusChange, { ...finalBlocklet, error: { message: error.message } });
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// 根据情况更新 route table, 会判断只有包含多 interfaces 的 DID 才会更新 route table
|
|
384
|
+
if (!['true', '1'].includes(process.env.ABT_NODE_DISABLE_BLUE_GREEN)) {
|
|
385
|
+
manager.emit(BlockletEvents.blueOrGreenStarted, {
|
|
386
|
+
blocklet: resultBlocklet,
|
|
387
|
+
componentDids: inputComponentDids,
|
|
388
|
+
context,
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
if (throwOnError && errorDescription) {
|
|
393
|
+
throw new Error(errorDescription);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
return resultBlocklet;
|
|
397
|
+
} finally {
|
|
398
|
+
if (shouldLock) {
|
|
399
|
+
await startLock.releaseLock(lockName);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Internal start implementation
|
|
406
|
+
*/
|
|
407
|
+
async function _start(
|
|
408
|
+
manager,
|
|
409
|
+
{
|
|
410
|
+
blocklet: inputBlocklet,
|
|
411
|
+
did,
|
|
412
|
+
throwOnError,
|
|
413
|
+
checkHealthImmediately = false,
|
|
414
|
+
e2eMode = false,
|
|
415
|
+
componentDids,
|
|
416
|
+
operator: _operator,
|
|
417
|
+
onStarted,
|
|
418
|
+
onError,
|
|
419
|
+
},
|
|
420
|
+
context
|
|
421
|
+
) {
|
|
422
|
+
const operator = _operator || context?.user?.did;
|
|
423
|
+
|
|
424
|
+
logger.info('start blocklet', {
|
|
425
|
+
did: did || inputBlocklet.meta.did,
|
|
426
|
+
componentDids,
|
|
427
|
+
throwOnError,
|
|
428
|
+
checkHealthImmediately,
|
|
429
|
+
e2eMode,
|
|
430
|
+
operator,
|
|
431
|
+
});
|
|
432
|
+
// should check blocklet integrity
|
|
433
|
+
const blocklet1 = inputBlocklet || (await manager.ensureBlocklet(did, { e2eMode }));
|
|
434
|
+
|
|
435
|
+
did = blocklet1.meta.did; // eslint-disable-line no-param-reassign
|
|
436
|
+
|
|
437
|
+
// validate requirement and engine
|
|
438
|
+
await validateBlocklet(blocklet1);
|
|
439
|
+
await validateBlockletChainInfo(blocklet1);
|
|
440
|
+
|
|
441
|
+
if (!hasRunnableComponent(blocklet1)) {
|
|
442
|
+
throw new Error('No runnable component found');
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
const entryComponentIds = [];
|
|
446
|
+
const nonEntryComponentIds = [];
|
|
447
|
+
const componentDidsSet = new Set(componentDids);
|
|
448
|
+
try {
|
|
449
|
+
await forEachBlocklet(
|
|
450
|
+
blocklet1,
|
|
451
|
+
(b) => {
|
|
452
|
+
if (!componentDidsSet.has(b.meta.did)) {
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
if (b.meta.group === BlockletGroup.gateway) {
|
|
457
|
+
nonEntryComponentIds.push(b.meta.did);
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
const engine = getBlockletEngine(b.meta);
|
|
462
|
+
if (engine.interpreter === 'blocklet') {
|
|
463
|
+
nonEntryComponentIds.push(b.meta.did);
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
if (!hasStartEngine(b.meta)) {
|
|
468
|
+
nonEntryComponentIds.push(b.meta.did);
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
entryComponentIds.push(b.meta.did);
|
|
472
|
+
},
|
|
473
|
+
{ parallel: true, concurrencyLimit: 4 }
|
|
474
|
+
);
|
|
475
|
+
if (nonEntryComponentIds.length) {
|
|
476
|
+
for (const subDid of nonEntryComponentIds) {
|
|
477
|
+
onStarted?.(subDid);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
} catch (err) {
|
|
481
|
+
logger.error('Failed to categorize components into entry and non-entry types', { error: err.message });
|
|
482
|
+
throw err;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
if (!entryComponentIds.length) {
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
try {
|
|
490
|
+
// check required config
|
|
491
|
+
for (const component of blocklet1.children) {
|
|
492
|
+
if (!entryComponentIds.includes(component.meta.did)) {
|
|
493
|
+
continue;
|
|
494
|
+
}
|
|
495
|
+
if (!shouldSkipComponent(component.meta.did, entryComponentIds)) {
|
|
496
|
+
const missingProps = getComponentMissingConfigs(component, blocklet1);
|
|
497
|
+
if (missingProps.length) {
|
|
498
|
+
throw new Error(
|
|
499
|
+
`Missing required configuration to start ${component.meta.title}: ${missingProps
|
|
500
|
+
.map((x) => x.key)
|
|
501
|
+
.join(',')}`
|
|
502
|
+
);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
blocklet1.status = BlockletStatus.starting;
|
|
508
|
+
const blocklet = await ensureAppPortsNotOccupied({
|
|
509
|
+
blocklet: blocklet1,
|
|
510
|
+
componentDids: entryComponentIds,
|
|
511
|
+
states,
|
|
512
|
+
manager,
|
|
513
|
+
});
|
|
514
|
+
|
|
515
|
+
const nodeInfo = await states.node.read();
|
|
516
|
+
|
|
517
|
+
const nodeEnvironments = await states.node.getEnvironments(nodeInfo);
|
|
518
|
+
|
|
519
|
+
if (checkDockerRunHistory(nodeInfo)) {
|
|
520
|
+
const needChownDirs = [];
|
|
521
|
+
await forEachBlocklet(blocklet, (b, { ancestors }) => {
|
|
522
|
+
if (!b.meta?.docker?.image || b.meta?.docker?.runBaseScript) {
|
|
523
|
+
return;
|
|
524
|
+
}
|
|
525
|
+
const env = getRuntimeEnvironments(b, nodeEnvironments, ancestors);
|
|
526
|
+
needChownDirs.push(env.BLOCKLET_APP_DIR);
|
|
527
|
+
needChownDirs.push(env.BLOCKLET_DATA_DIR);
|
|
528
|
+
needChownDirs.push(env.BLOCKLET_LOG_DIR);
|
|
529
|
+
});
|
|
530
|
+
await dockerExecChown({ name: `${blocklet?.meta?.did}-before-start`, dirs: needChownDirs });
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
const getHookFn =
|
|
534
|
+
(hookName) =>
|
|
535
|
+
async (b, { env }) => {
|
|
536
|
+
const hookArgs = getHookArgs(b);
|
|
537
|
+
const needRunDocker = await checkNeedRunDocker(b.meta, env, nodeInfo, isExternalBlocklet(blocklet));
|
|
538
|
+
if (!b.meta.scripts?.[hookName]) {
|
|
539
|
+
return null;
|
|
540
|
+
}
|
|
541
|
+
if (needRunDocker) {
|
|
542
|
+
return dockerExec({
|
|
543
|
+
blocklet,
|
|
544
|
+
meta: b.meta,
|
|
545
|
+
script: b.meta.scripts?.[hookName],
|
|
546
|
+
hookName,
|
|
547
|
+
nodeInfo,
|
|
548
|
+
env,
|
|
549
|
+
...hookArgs,
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
return hooks[hookName](b, {
|
|
553
|
+
appDir: b.env.appDir,
|
|
554
|
+
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
555
|
+
env,
|
|
556
|
+
did, // root blocklet did,
|
|
557
|
+
teamManager: manager.teamManager,
|
|
558
|
+
...hookArgs,
|
|
559
|
+
});
|
|
560
|
+
};
|
|
561
|
+
|
|
562
|
+
await startBlockletProcess(blocklet, {
|
|
563
|
+
...context,
|
|
564
|
+
preFlight: getHookFn('preFlight'),
|
|
565
|
+
preStart: getHookFn('preStart'),
|
|
566
|
+
postStart: getHookFn('postStart'),
|
|
567
|
+
nodeEnvironments,
|
|
568
|
+
nodeInfo: await states.node.read(),
|
|
569
|
+
e2eMode,
|
|
570
|
+
componentDids: entryComponentIds,
|
|
571
|
+
configSynchronizer: manager.configSynchronizer,
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
// check blocklet healthy
|
|
575
|
+
const { startTimeout, minConsecutiveTime } = getHealthyCheckTimeout(blocklet, {
|
|
576
|
+
checkHealthImmediately,
|
|
577
|
+
componentDids,
|
|
578
|
+
});
|
|
579
|
+
|
|
580
|
+
const params = {
|
|
581
|
+
did,
|
|
582
|
+
context,
|
|
583
|
+
minConsecutiveTime,
|
|
584
|
+
timeout: startTimeout,
|
|
585
|
+
componentDids: entryComponentIds,
|
|
586
|
+
};
|
|
587
|
+
|
|
588
|
+
await manager._onCheckIfStarted(params, { throwOnError });
|
|
589
|
+
|
|
590
|
+
for (const subDid of entryComponentIds) {
|
|
591
|
+
onStarted?.(subDid);
|
|
592
|
+
}
|
|
593
|
+
} catch (err) {
|
|
594
|
+
const status = await states.blocklet.getBlockletStatus(did);
|
|
595
|
+
if ([BlockletStatus.stopping, BlockletStatus.stopped].includes(status)) {
|
|
596
|
+
logger.info('Failed to start blocklet maybe due to manually stopped');
|
|
597
|
+
}
|
|
598
|
+
for (const subDid of entryComponentIds) {
|
|
599
|
+
onError?.(subDid, err);
|
|
600
|
+
}
|
|
601
|
+
if (throwOnError) {
|
|
602
|
+
throw err;
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
module.exports = {
|
|
608
|
+
startRequiredComponents,
|
|
609
|
+
start,
|
|
610
|
+
_start,
|
|
611
|
+
};
|