@abtnode/core 1.16.47-beta-20250807-110715-19ad6b43 → 1.16.47

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.
@@ -435,33 +435,31 @@ class DiskBlockletManager extends BaseBlockletManager {
435
435
  await this.ensureAutoBackupJobs();
436
436
  await this.ensureAutoCheckUpdateJobs();
437
437
 
438
- if (process.env.ABT_NODE_ENABLE_ENSURE_BLOCKLET_RUNNING !== 'ignore') {
439
- ensureBlockletRunning.initialize({
440
- restart: async (params) => {
441
- await this.restart(params);
442
- },
443
- stop: async (params) => {
444
- await this.stop(params);
445
- },
446
- createAuditLog: (params) => this.createAuditLog(params),
447
- notification: (did, title, description, severity) => {
448
- try {
449
- this._createNotification(did, {
450
- title,
451
- description,
452
- action: `/blocklets/${did}/overview`,
453
- blockletDashboardAction: `${WELLKNOWN_SERVICE_PATH_PREFIX}/admin/blocklets`,
454
- entityType: 'blocklet',
455
- entityId: did,
456
- severity,
457
- });
458
- } catch (err) {
459
- logger.error('create notification failed', { err });
460
- }
461
- },
462
- checkSystemHighLoad: (...args) => this.nodeAPI.runtimeMonitor.checkSystemHighLoad(...args),
463
- });
464
- }
438
+ ensureBlockletRunning.initialize({
439
+ restart: async (params) => {
440
+ await this.restart(params);
441
+ },
442
+ stop: async (params) => {
443
+ await this.stop(params);
444
+ },
445
+ createAuditLog: (params) => this.createAuditLog(params),
446
+ notification: (did, title, description, severity) => {
447
+ try {
448
+ this._createNotification(did, {
449
+ title,
450
+ description,
451
+ action: `/blocklets/${did}/overview`,
452
+ blockletDashboardAction: `${WELLKNOWN_SERVICE_PATH_PREFIX}/admin/blocklets`,
453
+ entityType: 'blocklet',
454
+ entityId: did,
455
+ severity,
456
+ });
457
+ } catch (err) {
458
+ logger.error('create notification failed', { err });
459
+ }
460
+ },
461
+ checkSystemHighLoad: (...args) => this.nodeAPI.runtimeMonitor.checkSystemHighLoad(...args),
462
+ });
465
463
  }
466
464
 
467
465
  async ensureJobs({ queue, getJobId, find, entity, action, interval, restoreCancelled }) {
@@ -922,7 +920,6 @@ class DiskBlockletManager extends BaseBlockletManager {
922
920
  nodeInfo,
923
921
  env,
924
922
  ...hookArgs,
925
- timeout: 20000,
926
923
  });
927
924
  }
928
925
  return hooks[hookName](b, {
@@ -12,16 +12,10 @@ const inProgressStatuses = [BlockletStatus.stopping, BlockletStatus.restarting,
12
12
  class EnsureBlockletRunning {
13
13
  initialized = false;
14
14
 
15
- firstChecked = false;
15
+ whenCycleCheck = false;
16
16
 
17
17
  // 每次任务的最小间隔时间
18
- checkInterval = +process.env.ABT_NODE_ENSURE_RUNNING_CHECK_INTERVAL || 60 * 1000;
19
-
20
- // 首次任务的延迟时间
21
- deferredTime = +process.env.ABT_NODE_ENSURE_RUNNING_DEFERRED_TIME || 30 * 1000;
22
-
23
- // 每个重启任务(did + componentDids)的重启间隔为 2 min,如果 2 min 内重启过,就不会再重启
24
- restartInterval = 1000 * 60 * 2;
18
+ checkInterval = +process.env.ABT_NODE_ENSURE_RUNNING_CHECK_INTERVAL || 180 * 1000;
25
19
 
26
20
  everyBlockletCheckInterval = 2000;
27
21
 
@@ -41,7 +35,7 @@ class EnsureBlockletRunning {
41
35
 
42
36
  fakeRunningBlocklets = {};
43
37
 
44
- fakeRunningBlockletsTimes = {};
38
+ needRestartBlocklets = {};
45
39
 
46
40
  restartingBlocklets = {};
47
41
 
@@ -52,23 +46,36 @@ class EnsureBlockletRunning {
52
46
  // Ease to mock
53
47
  isBlockletPortHealthy = isBlockletPortHealthy;
54
48
 
55
- isBlockletPortHealthyWithRetries = async (blocklet, isDoing = false) => {
49
+ isBlockletPortHealthyWithRetries = async (blocklet, fastCheck = false) => {
56
50
  let error;
57
- const maxAttempts = this.firstChecked ? 10 : 2;
58
- const timeout = this.firstChecked ? 6000 : 3000;
51
+ if (!this.whenCycleCheck) {
52
+ try {
53
+ // eslint-disable-next-line no-await-in-loop
54
+ await this.isBlockletPortHealthy(blocklet, {
55
+ minConsecutiveTime: 200,
56
+ timeout: 1000,
57
+ });
58
+ return true;
59
+ } catch (e) {
60
+ logger.error('blocklet port is not healthy', e);
61
+ }
62
+ return false;
63
+ }
59
64
 
60
- for (let attempt = 0; attempt < maxAttempts; attempt++) {
65
+ for (let attempt = 0; attempt < 10; attempt++) {
61
66
  try {
62
67
  // eslint-disable-next-line no-await-in-loop
63
68
  await this.isBlockletPortHealthy(blocklet, {
64
69
  minConsecutiveTime: 3000,
65
- timeout,
70
+ timeout: 6000,
66
71
  });
67
72
  return true;
68
73
  } catch (e) {
69
74
  error = e;
70
75
  // eslint-disable-next-line no-await-in-loop
71
- await sleep(isDoing ? this.everyBlockletDoingInterval : this.everyBlockletCheckInterval);
76
+ await sleep(
77
+ fastCheck && this.whenCycleCheck ? this.everyBlockletDoingInterval : this.everyBlockletCheckInterval
78
+ );
72
79
  }
73
80
  }
74
81
  logger.error('blocklet port is not healthy', error);
@@ -91,7 +98,9 @@ class EnsureBlockletRunning {
91
98
  this.checkSystemHighLoad = checkSystemHighLoad;
92
99
  logger.info('check and fix blocklet status interval', this.checkInterval);
93
100
  const task = async () => {
94
- await sleep(this.checkInterval);
101
+ if (this.whenCycleCheck) {
102
+ await sleep(this.checkInterval);
103
+ }
95
104
  try {
96
105
  await this.checkAndFix();
97
106
  } catch (e) {
@@ -116,91 +125,72 @@ class EnsureBlockletRunning {
116
125
 
117
126
  checkAndFix = async () => {
118
127
  logger.info('check and fix blocklet status');
119
- if (process.env.ABT_NODE_RESTART_RUNNING_COMPONENT === '1') {
120
- logger.info('skip check and fix blocklet status because ABT_NODE_RESTART_RUNNING_COMPONENT is 1');
121
- return;
122
- }
123
-
124
128
  const systemHighLoad = this.checkSystemHighLoad({
125
129
  maxCpus: this.highLoadCpu,
126
130
  maxMem: this.highLoadMemory,
127
131
  maxDisk: this.highLoadDisk,
128
132
  });
129
133
 
130
- if (systemHighLoad.isHighLoad) {
134
+ if (this.whenCycleCheck && systemHighLoad.isHighLoad) {
131
135
  logger.warn('Skip once ensure blocklet running because system high load', systemHighLoad);
132
136
  return;
133
137
  }
138
+
134
139
  this.runningBlocklets = {};
135
140
  this.fakeRunningBlocklets = {};
136
- this.fakeRunningBlockletsTimes = {};
141
+ this.needRestartBlocklets = {};
137
142
 
143
+ const startTime = Date.now();
138
144
  try {
139
145
  await this.getRunningBlocklets();
140
146
  await this.getFakeRunningBlocklets();
141
- if (process.env.ABT_NODE_ENSURE_RUNNING_SET_FAKE_RUNNING_TO_WAITING === '1') {
147
+ if (!this.whenCycleCheck) {
142
148
  await this.setFakeRunningToWaiting();
143
149
  }
144
150
  await this.restartFakeRunningBlocklets();
145
151
  } catch (e) {
146
152
  logger.error('ensure blocklet status failed', e);
147
153
  }
154
+ logger.info(
155
+ `ensure blocklet status finished in ${Date.now() - startTime}ms. It's server first start: ${!this.whenCycleCheck}`
156
+ );
148
157
  this.runningRootBlocklets = {};
149
- this.firstChecked = true;
158
+ this.whenCycleCheck = true;
150
159
  };
151
160
 
152
161
  getRunningBlocklets = async () => {
153
- const blocklets = await this.states.blocklet.getBlocklets({
154
- status: { $in: [BlockletStatus.running, BlockletStatus.waiting, BlockletStatus.starting] },
155
- });
156
- for (const realBlocklet of blocklets) {
157
- const { did } = realBlocklet.meta;
158
- if (realBlocklet.children) {
159
- for (const childBlocklet of realBlocklet.children) {
160
- if (childBlocklet.status === BlockletStatus.running || childBlocklet.status === BlockletStatus.waiting) {
161
- if (!this.runningBlocklets[did]) {
162
- this.runningBlocklets[did] = [];
163
- }
164
- if (this.runningBlocklets[did].find((b) => b.meta.did === childBlocklet.meta.did)) {
165
- continue;
166
- }
167
- this.runningBlocklets[did].push(childBlocklet);
168
- this.runningRootBlocklets[did] = realBlocklet;
169
- }
170
- }
171
- }
172
- }
173
-
174
- const blockletDoings = await this.states.blocklet.getBlocklets({
175
- status: {
176
- $in: inProgressStatuses,
177
- },
178
- });
162
+ const runningStatuses = this.whenCycleCheck
163
+ ? [BlockletStatus.running, BlockletStatus.waiting, BlockletStatus.starting]
164
+ : [BlockletStatus.running, BlockletStatus.waiting, BlockletStatus.starting, BlockletStatus.error];
179
165
 
180
- for (const rootBlocklet of blockletDoings) {
166
+ const blocklets = await this.states.blocklet.getBlocklets();
167
+ for (const rootBlocklet of blocklets) {
181
168
  const { did } = rootBlocklet.meta;
182
169
  if (rootBlocklet.children) {
183
170
  for (const childBlocklet of rootBlocklet.children) {
184
- if (inProgressStatuses.includes(childBlocklet.status)) {
185
- if (this.runningBlocklets[did]?.find((b) => b.meta.did === childBlocklet.meta.did)) {
186
- continue;
187
- }
171
+ const isRunning = runningStatuses.includes(childBlocklet.status);
172
+ const isInProgress = inProgressStatuses.includes(childBlocklet.status);
173
+ if (isRunning || isInProgress) {
188
174
  if (!this.runningBlocklets[did]) {
189
175
  this.runningBlocklets[did] = [];
190
176
  }
177
+ if (this.runningBlocklets[did].find((b) => b.meta.did === childBlocklet.meta.did)) {
178
+ continue;
179
+ }
191
180
  this.runningBlocklets[did].push(childBlocklet);
181
+ this.runningRootBlocklets[did] = rootBlocklet;
192
182
  }
193
183
  }
194
184
  }
195
185
  }
186
+
196
187
  logger.info('get running blocklets', Object.keys(this.runningBlocklets).length);
197
188
  };
198
189
 
199
190
  getFakeRunningBlocklets = async () => {
200
- this.fakeRunningBlocklets = {};
201
- const blockletDids = Object.keys(this.runningBlocklets);
191
+ const rootDids = Object.keys(this.runningBlocklets);
202
192
  await pAll(
203
- blockletDids.map((did) => {
193
+ rootDids.map((did) => {
204
194
  return async () => {
205
195
  const blocklets = this.runningBlocklets[did];
206
196
  // eslint-disable-next-line
@@ -241,7 +231,7 @@ class EnsureBlockletRunning {
241
231
  );
242
232
  };
243
233
  }),
244
- { concurrency: 3 }
234
+ { concurrency: 8 }
245
235
  );
246
236
 
247
237
  logger.info('get fake running blocklets', Object.keys(this.fakeRunningBlocklets).length);
@@ -257,7 +247,9 @@ class EnsureBlockletRunning {
257
247
  blockletDids.map((did) => {
258
248
  return async () => {
259
249
  const blocklets = this.fakeRunningBlocklets[did];
260
- const componentDids = blocklets.filter((b) => b.status === BlockletStatus.running).map((b) => b.meta.did);
250
+ const componentDids = blocklets
251
+ .filter((b) => b.status === BlockletStatus.running || b.status === BlockletStatus.waiting)
252
+ .map((b) => b.meta.did);
261
253
  try {
262
254
  // eslint-disable-next-line
263
255
  await this.states.blocklet.setBlockletStatus(did, BlockletStatus.waiting, { componentDids });
@@ -266,17 +258,11 @@ class EnsureBlockletRunning {
266
258
  }
267
259
  };
268
260
  }),
269
- { concurrency: 4 }
261
+ { concurrency: 8 }
270
262
  );
271
263
  };
272
264
 
273
265
  restartFakeRunningBlocklets = async () => {
274
- for (const key of Object.keys(this.restartingBlocklets)) {
275
- if (Date.now() - this.restartingBlocklets[key] > this.restartInterval) {
276
- delete this.restartingBlocklets[key];
277
- }
278
- }
279
-
280
266
  // blocklet 一组组重启
281
267
  const blockletDids = Object.keys(this.fakeRunningBlocklets);
282
268
  await pAll(
@@ -286,7 +272,8 @@ class EnsureBlockletRunning {
286
272
  const componentDids = blocklets.map((b) => b.meta.did);
287
273
  if (componentDids.length > 0) {
288
274
  const key = `${did}-${componentDids.join('-')}`;
289
- if (this.restartingBlocklets[key]) {
275
+ this.needRestartBlocklets[key] = true;
276
+ if (this.restartingBlocklets[key] && this.restartingBlocklets[key] + this.checkInterval < Date.now()) {
290
277
  return;
291
278
  }
292
279
  this.restartingBlocklets[key] = Date.now();
@@ -294,31 +281,36 @@ class EnsureBlockletRunning {
294
281
  const blockletDisplayName = this.getDisplayNameByRootDid(did);
295
282
  const restartTitle = 'Blocklet health check failed';
296
283
  const restartDescription = `Blocklet ${blockletDisplayName} with components ${componentDids.map((v) => this.getDisplayName(blocklets.find((b) => b.meta.did === v))).join(', ')} health check failed, restarting...`;
297
- this.notification(did, restartTitle, restartDescription, 'warning');
284
+ if (this.whenCycleCheck) {
285
+ this.notification(did, restartTitle, restartDescription, 'warning');
286
+ }
298
287
 
299
288
  try {
300
289
  logger.info('restart blocklet:', did, componentDids);
301
290
  await this.restart({ did, componentDids, checkHealthImmediately: true });
302
- this.createAuditLog({
303
- action: 'ensureBlockletRunning',
304
- args: {
305
- teamDid: did,
306
- componentDids,
307
- },
308
- context: {
309
- user: {
310
- did,
311
- role: 'daemon',
312
- blockletDid: did,
313
- fullName: blockletDisplayName,
314
- elevated: false,
291
+ if (this.whenCycleCheck) {
292
+ this.createAuditLog({
293
+ action: 'ensureBlockletRunning',
294
+ args: {
295
+ teamDid: did,
296
+ componentDids,
315
297
  },
316
- },
317
- result: {
318
- title: restartTitle,
319
- description: restartDescription,
320
- },
321
- });
298
+ context: {
299
+ user: {
300
+ did,
301
+ role: 'daemon',
302
+ blockletDid: did,
303
+ fullName: blockletDisplayName,
304
+ elevated: false,
305
+ },
306
+ },
307
+ result: {
308
+ title: restartTitle,
309
+ description: restartDescription,
310
+ },
311
+ });
312
+ }
313
+
322
314
  delete this.restartingBlocklets[key];
323
315
  } catch (e) {
324
316
  logger.error('restart blocklet failed', did, componentDids, e);
@@ -327,15 +319,16 @@ class EnsureBlockletRunning {
327
319
  }
328
320
  this.errorStartBlocklets[key] += 1;
329
321
 
330
- // 如果重启失败次数超过 3 次,则设置为 stopped
331
- if (this.errorStartBlocklets[key] >= 3) {
322
+ // 如果重启失败次数超过 3 次,则发送通知, 如果 server 是第一次启动遇到失败,则立刻发送通知
323
+ if (this.errorStartBlocklets[key] >= 3 || !this.whenCycleCheck) {
332
324
  const title = 'Restart blocklet failed when health check failed';
333
325
  const description = `Restart blocklet ${blockletDisplayName} with components ${componentDids.map((v) => this.getDisplayName(blocklets.find((b) => b.meta.did === v))).join(', ')} failed`;
334
326
  this.notification(did, title, description, 'error');
335
327
  delete this.errorStartBlocklets[key];
336
- logger.error('restart many times blocklet failed, set stopped', did, componentDids, e);
328
+ logger.error('restart many times blocklet failed', did, componentDids, e);
337
329
  try {
338
- await this.stop({ did, componentDids });
330
+ // 失败了应该保持 error 状态
331
+ await this.states.blocklet.setBlockletStatus(did, BlockletStatus.error, { componentDids });
339
332
  this.createAuditLog({
340
333
  action: 'ensureBlockletRunning',
341
334
  args: {
@@ -358,14 +351,14 @@ class EnsureBlockletRunning {
358
351
  },
359
352
  });
360
353
  } catch (err) {
361
- logger.error('set blocklet stopped failed', did, componentDids, err);
354
+ logger.error('ensure blocklet running, create audit log failed', did, componentDids, err);
362
355
  }
363
356
  }
364
357
  }
365
358
  }
366
359
  };
367
360
  }),
368
- { concurrency: 2 }
361
+ { concurrency: 8 }
369
362
  );
370
363
  };
371
364
  }
@@ -38918,7 +38918,7 @@ module.exports = require("zlib");
38918
38918
  /***/ ((module) => {
38919
38919
 
38920
38920
  "use strict";
38921
- module.exports = /*#__PURE__*/JSON.parse('{"name":"@abtnode/core","publishConfig":{"access":"public"},"version":"1.16.46","description":"","main":"lib/index.js","files":["lib"],"scripts":{"lint":"eslint tests lib --ignore-pattern \'tests/assets/*\'","lint:fix":"eslint --fix tests lib","test":"node tools/jest.js","coverage":"npm run test -- --coverage"},"keywords":[],"author":"wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)","license":"Apache-2.0","dependencies":{"@abtnode/analytics":"1.16.46","@abtnode/auth":"1.16.46","@abtnode/certificate-manager":"1.16.46","@abtnode/client":"1.16.46","@abtnode/constant":"1.16.46","@abtnode/cron":"1.16.46","@abtnode/db-cache":"1.16.46","@abtnode/docker-utils":"1.16.46","@abtnode/logger":"1.16.46","@abtnode/models":"1.16.46","@abtnode/queue":"1.16.46","@abtnode/rbac":"1.16.46","@abtnode/router-provider":"1.16.46","@abtnode/static-server":"1.16.46","@abtnode/timemachine":"1.16.46","@abtnode/util":"1.16.46","@aigne/aigne-hub":"^0.4.5","@arcblock/did":"1.21.2","@arcblock/did-connect-js":"1.21.2","@arcblock/did-ext":"1.21.2","@arcblock/did-motif":"^1.1.14","@arcblock/did-util":"1.21.2","@arcblock/event-hub":"1.21.2","@arcblock/jwt":"1.21.2","@arcblock/pm2-events":"^0.0.5","@arcblock/validator":"1.21.2","@arcblock/vc":"1.21.2","@blocklet/constant":"1.16.46","@blocklet/did-space-js":"^1.1.13","@blocklet/env":"1.16.46","@blocklet/error":"^0.2.5","@blocklet/meta":"1.16.46","@blocklet/resolver":"1.16.46","@blocklet/sdk":"1.16.46","@blocklet/store":"1.16.46","@blocklet/theme":"^3.0.42","@fidm/x509":"^1.2.1","@ocap/mcrypto":"1.21.2","@ocap/util":"1.21.2","@ocap/wallet":"1.21.2","@slack/webhook":"^5.0.4","archiver":"^7.0.1","axios":"^1.7.9","axon":"^2.0.3","chalk":"^4.1.2","cross-spawn":"^7.0.3","dayjs":"^1.11.13","deep-diff":"^1.0.2","detect-port":"^1.5.1","envfile":"^7.1.0","escape-string-regexp":"^4.0.0","fast-glob":"^3.3.2","filesize":"^10.1.1","flat":"^5.0.2","fs-extra":"^11.2.0","get-port":"^5.1.1","hasha":"^5.2.2","is-base64":"^1.1.0","is-cidr":"4","is-ip":"3","is-url":"^1.2.4","joi":"17.12.2","joi-extension-semver":"^5.0.0","js-yaml":"^4.1.0","kill-port":"^2.0.1","lodash":"^4.17.21","node-stream-zip":"^1.15.0","p-all":"^3.0.0","p-limit":"^3.1.0","p-map":"^4.0.0","p-retry":"^4.6.2","p-wait-for":"^3.2.0","private-ip":"^2.3.4","rate-limiter-flexible":"^5.0.5","read-last-lines":"^1.8.0","semver":"^7.6.3","sequelize":"^6.35.0","shelljs":"^0.8.5","slugify":"^1.6.6","ssri":"^8.0.1","stream-throttle":"^0.1.3","stream-to-promise":"^3.0.0","systeminformation":"^5.23.3","tail":"^2.2.4","tar":"^6.1.11","transliteration":"^2.3.5","ua-parser-js":"^1.0.2","ufo":"^1.5.3","uuid":"^11.1.0","valid-url":"^1.0.9","which":"^2.0.2","xbytes":"^1.8.0"},"devDependencies":{"expand-tilde":"^2.0.2","express":"^4.18.2","jest":"^29.7.0","unzipper":"^0.10.11"},"gitHead":"e5764f753181ed6a7c615cd4fc6682aacf0cb7cd"}');
38921
+ module.exports = /*#__PURE__*/JSON.parse('{"name":"@abtnode/core","publishConfig":{"access":"public"},"version":"1.16.46","description":"","main":"lib/index.js","files":["lib"],"scripts":{"lint":"eslint tests lib --ignore-pattern \'tests/assets/*\'","lint:fix":"eslint --fix tests lib","test":"node tools/jest.js","coverage":"npm run test -- --coverage"},"keywords":[],"author":"wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)","license":"Apache-2.0","dependencies":{"@abtnode/analytics":"1.16.46","@abtnode/auth":"1.16.46","@abtnode/certificate-manager":"1.16.46","@abtnode/client":"1.16.46","@abtnode/constant":"1.16.46","@abtnode/cron":"1.16.46","@abtnode/db-cache":"1.16.46","@abtnode/docker-utils":"1.16.46","@abtnode/logger":"1.16.46","@abtnode/models":"1.16.46","@abtnode/queue":"1.16.46","@abtnode/rbac":"1.16.46","@abtnode/router-provider":"1.16.46","@abtnode/static-server":"1.16.46","@abtnode/timemachine":"1.16.46","@abtnode/util":"1.16.46","@aigne/aigne-hub":"^0.4.6","@arcblock/did":"1.21.2","@arcblock/did-connect-js":"1.21.2","@arcblock/did-ext":"1.21.2","@arcblock/did-motif":"^1.1.14","@arcblock/did-util":"1.21.2","@arcblock/event-hub":"1.21.2","@arcblock/jwt":"1.21.2","@arcblock/pm2-events":"^0.0.5","@arcblock/validator":"1.21.2","@arcblock/vc":"1.21.2","@blocklet/constant":"1.16.46","@blocklet/did-space-js":"^1.1.14","@blocklet/env":"1.16.46","@blocklet/error":"^0.2.5","@blocklet/meta":"1.16.46","@blocklet/resolver":"1.16.46","@blocklet/sdk":"1.16.46","@blocklet/store":"1.16.46","@blocklet/theme":"^3.1.3","@fidm/x509":"^1.2.1","@ocap/mcrypto":"1.21.2","@ocap/util":"1.21.2","@ocap/wallet":"1.21.2","@slack/webhook":"^5.0.4","archiver":"^7.0.1","axios":"^1.7.9","axon":"^2.0.3","chalk":"^4.1.2","cross-spawn":"^7.0.3","dayjs":"^1.11.13","deep-diff":"^1.0.2","detect-port":"^1.5.1","envfile":"^7.1.0","escape-string-regexp":"^4.0.0","fast-glob":"^3.3.2","filesize":"^10.1.1","flat":"^5.0.2","fs-extra":"^11.2.0","get-port":"^5.1.1","hasha":"^5.2.2","is-base64":"^1.1.0","is-cidr":"4","is-ip":"3","is-url":"^1.2.4","joi":"17.12.2","joi-extension-semver":"^5.0.0","js-yaml":"^4.1.0","kill-port":"^2.0.1","lodash":"^4.17.21","node-stream-zip":"^1.15.0","p-all":"^3.0.0","p-limit":"^3.1.0","p-map":"^4.0.0","p-retry":"^4.6.2","p-wait-for":"^3.2.0","private-ip":"^2.3.4","rate-limiter-flexible":"^5.0.5","read-last-lines":"^1.8.0","semver":"^7.6.3","sequelize":"^6.35.0","shelljs":"^0.8.5","slugify":"^1.6.6","ssri":"^8.0.1","stream-throttle":"^0.1.3","stream-to-promise":"^3.0.0","systeminformation":"^5.23.3","tail":"^2.2.4","tar":"^6.1.11","transliteration":"^2.3.5","ua-parser-js":"^1.0.2","ufo":"^1.5.3","uuid":"^11.1.0","valid-url":"^1.0.9","which":"^2.0.2","xbytes":"^1.8.0"},"devDependencies":{"expand-tilde":"^2.0.2","express":"^4.18.2","jest":"^29.7.0","unzipper":"^0.10.11"},"gitHead":"e5764f753181ed6a7c615cd4fc6682aacf0cb7cd"}');
38922
38922
 
38923
38923
  /***/ }),
38924
38924
 
@@ -234,7 +234,8 @@ class NodeRuntimeMonitor extends EventEmitter {
234
234
  if (cpus.some((v) => v > maxCpus) && memory > maxMem) {
235
235
  highType = 'cpu and memory';
236
236
  }
237
- if (disks.some((v) => v > maxDisk)) {
237
+ // 1 表示虚拟盘,不参与计算
238
+ if (disks.some((v) => v !== 1 && v > maxDisk)) {
238
239
  highType = 'disk';
239
240
  }
240
241
  if (highType) {
@@ -495,7 +495,7 @@ class TeamManager extends EventEmitter {
495
495
  // 获取 notification state
496
496
  const notificationState = await this.getNotificationState(teamDid);
497
497
  if (!notificationState) {
498
- throw new Error('notificationState not found');
498
+ return undefined;
499
499
  }
500
500
 
501
501
  // 检查通知是否已存在
@@ -505,7 +505,7 @@ class TeamManager extends EventEmitter {
505
505
 
506
506
  if (!receivers?.length && process.env.NODE_ENV !== 'test') {
507
507
  logger.warn('No valid receivers', { teamDid, receiver });
508
- throw new Error('No valid receivers');
508
+ return undefined;
509
509
  }
510
510
 
511
511
  const notificationActor = notification?.activity?.actor || payload.activity?.actor;
@@ -145,7 +145,7 @@ const getBlockletEngineNameByPlatform = (meta) => getBlockletEngine(meta).interp
145
145
  const startLock = new DBCache(() => ({
146
146
  ...getAbtNodeRedisAndSQLiteUrl(),
147
147
  prefix: 'blocklet-start-locks2',
148
- ttl: 1000 * 60 * 1,
148
+ ttl: 1000 * 60 * 3,
149
149
  }));
150
150
 
151
151
  const blockletCache = new DBCache(() => ({
@@ -819,23 +819,21 @@ const startBlockletProcess = async (
819
819
  * @returns
820
820
  */
821
821
  async (b, { ancestors }) => {
822
- const lockName = [
823
- blocklet.meta.did,
824
- blocklet.meta.version,
825
- blocklet.meta.group,
826
- b.meta.did,
827
- b.meta.version,
828
- b.meta.group,
829
- ].join('__');
822
+ const lockName = `${blocklet.meta.did}-${b.meta.did}`;
830
823
 
824
+ // 如果锁存在,则跳过执行
825
+ if (!(await startLock.hasExpired(lockName))) {
826
+ return;
827
+ }
831
828
  await startLock.acquire(lockName);
829
+
832
830
  try {
833
831
  await startBlockletTask(b, { ancestors });
834
832
  } finally {
835
833
  startLock.releaseLock(lockName);
836
834
  }
837
835
  },
838
- { parallel: true, concurrencyLimit: nodeInfo.enableDocker ? 2 : 4 }
836
+ { parallel: true, concurrencyLimit: 4 }
839
837
  );
840
838
  };
841
839
 
@@ -12,7 +12,7 @@ const { createDockerImage } = require('./create-docker-image');
12
12
 
13
13
  const lockFile = new DBCache(() => ({
14
14
  prefix: 'docker-exec-chown-locks',
15
- ttl: 1000 * 60 * 2,
15
+ ttl: 1000 * 60 * 3,
16
16
  ...getAbtNodeRedisAndSQLiteUrl(),
17
17
  }));
18
18
 
@@ -53,10 +53,14 @@ async function dockerExecChown({ name, dirs, code = 777, force = false }) {
53
53
  return `chmod ${code === 750 ? '' : '-R'} ${code} ${path.join(baseDir, dir.replace(process.env.ABT_NODE_DATA_DIR, ''))}`;
54
54
  })
55
55
  .join(' && ');
56
- const realName = parseDockerName(name, 'docker-exec-chown');
57
- const startTime = Date.now();
58
56
 
57
+ const startTime = Date.now();
58
+ const realName = parseDockerName(name, 'docker-exec-chown');
59
+ if (!(await lockFile.hasExpired(realName))) {
60
+ return;
61
+ }
59
62
  await lockFile.acquire(realName);
63
+
60
64
  try {
61
65
  await promiseSpawn(
62
66
  `docker rm -fv ${realName} > /dev/null 2>&1 || true && docker run --rm --name ${realName} ${volumes} ${image} sh -c '${command}'`,
@@ -2,10 +2,20 @@ const fs = require('fs').promises;
2
2
  const fse = require('fs-extra');
3
3
  const path = require('path');
4
4
  const promiseSpawn = require('@abtnode/util/lib/promise-spawn');
5
+ const { DBCache, getAbtNodeRedisAndSQLiteUrl } = require('@abtnode/db-cache');
5
6
  const logger = require('@abtnode/logger')('@abtnode/docker-exec');
7
+
6
8
  const parseDockerOptionsFromPm2 = require('./parse-docker-options-from-pm2');
7
9
  const { checkDockerInstalled } = require('./check-docker-installed');
8
10
 
11
+ const lock = new DBCache(() => {
12
+ return {
13
+ ...getAbtNodeRedisAndSQLiteUrl(),
14
+ prefix: 'docker-exec',
15
+ ttl: 1000 * 60 * 3,
16
+ };
17
+ });
18
+
9
19
  async function dockerExec({
10
20
  blocklet,
11
21
  meta,
@@ -15,7 +25,7 @@ async function dockerExec({
15
25
  runScriptDir,
16
26
  runScriptParams,
17
27
  nodeInfo,
18
- timeout = 10000,
28
+ timeout = 120_000,
19
29
  retry = 3,
20
30
  output,
21
31
  error,
@@ -40,8 +50,13 @@ async function dockerExec({
40
50
  await fs.writeFile(paramsFilePath, JSON.stringify(runScriptParams));
41
51
  }
42
52
 
43
- const command = `sh -c 'cd $BLOCKLET_APP_DIR && ${script}'`;
53
+ const lockKey = `${blockletDid}-${meta.name}-${hookName}`;
54
+ if (!(await lock.hasExpired(lockKey))) {
55
+ return;
56
+ }
57
+ await lock.acquire(lockKey);
44
58
 
59
+ const command = `sh -c 'cd $BLOCKLET_APP_DIR && ${script}'`;
45
60
  const options = await parseDockerOptionsFromPm2({
46
61
  options: {
47
62
  name: `${blockletDid}-${meta.name}-${hookName}`,
@@ -54,6 +69,7 @@ async function dockerExec({
54
69
  dockerNamePrefix: 'docker-exec',
55
70
  eventName: hookName,
56
71
  });
72
+
57
73
  const startTime = Date.now();
58
74
  try {
59
75
  await promiseSpawn(
@@ -65,12 +81,9 @@ async function dockerExec({
65
81
  { timeout, retry }
66
82
  );
67
83
  } finally {
84
+ await lock.releaseLock(lockKey);
68
85
  if (nodeInfo.isDockerInstalled) {
69
- await promiseSpawn(
70
- `docker rm -fv ${options.env.dockerName} > /dev/null 2>&1 || true`,
71
- {},
72
- { timeout: 1000 * 10, retry: 3 }
73
- );
86
+ await promiseSpawn(`docker rm -f ${options.env.dockerName} > /dev/null 2>&1 || true`, {}, { timeout: 1000 * 10 });
74
87
  }
75
88
  }
76
89
  logger.info(`dockerExec ${options.env.dockerName} cost time: ${Date.now() - startTime}ms`);
@@ -334,13 +334,8 @@ async function parseDockerOptionsFromPm2({
334
334
  user = `-u ${uid}:${gid}`;
335
335
  }
336
336
 
337
- try {
338
- await promiseSpawn(`docker rm -f ${name}`, { mute: true }, { timeout: 5 * 1000, retry: 0 });
339
- } catch (_) {
340
- // ignore error
341
- }
342
-
343
337
  nextOptions.script = `
338
+ docker rm -f ${name} > /dev/null 2>&1 || true && \
344
339
  docker run --rm --name ${name} \
345
340
  ${user} \
346
341
  ${volumes} \
@@ -350,7 +345,6 @@ async function parseDockerOptionsFromPm2({
350
345
  --cpus="${dockerEnv.BLOCKLET_DOCKER_CPUS}" \
351
346
  --memory="${dockerEnv.BLOCKLET_DOCKER_MEMORY}" \
352
347
  --memory-swap="${dockerEnv.BLOCKLET_DOCKER_MEMORY}" \
353
- --memory-swappiness=0 \
354
348
  --oom-kill-disable=false \
355
349
  --env-file ${dockerEnvFile} \
356
350
  ${dockerInfo.network} \
@@ -36,7 +36,7 @@ async function _ensureBun() {
36
36
  // 如果有 bun 且版本大于等于 BUN_VERSION, 则直接使用现有的 bun
37
37
  if (whichBun) {
38
38
  // 检查 bun 版本
39
- const bunVersion = shelljs.exec(`${whichBun} --version`).stdout.trim();
39
+ const bunVersion = shelljs.exec(`${whichBun} --version`, { silent: true }).stdout.trim();
40
40
  // 判断 bun 版本是否大于等于 BUN_VERSION, 应该用版本对比库
41
41
  if (semver.gte(bunVersion, BUN_VERSION)) {
42
42
  return whichBun.toString();
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.16.47-beta-20250807-110715-19ad6b43",
6
+ "version": "1.16.47",
7
7
  "description": "",
8
8
  "main": "lib/index.js",
9
9
  "files": [
@@ -19,23 +19,23 @@
19
19
  "author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
20
20
  "license": "Apache-2.0",
21
21
  "dependencies": {
22
- "@abtnode/analytics": "1.16.47-beta-20250807-110715-19ad6b43",
23
- "@abtnode/auth": "1.16.47-beta-20250807-110715-19ad6b43",
24
- "@abtnode/certificate-manager": "1.16.47-beta-20250807-110715-19ad6b43",
25
- "@abtnode/client": "1.16.47-beta-20250807-110715-19ad6b43",
26
- "@abtnode/constant": "1.16.47-beta-20250807-110715-19ad6b43",
27
- "@abtnode/cron": "1.16.47-beta-20250807-110715-19ad6b43",
28
- "@abtnode/db-cache": "1.16.47-beta-20250807-110715-19ad6b43",
29
- "@abtnode/docker-utils": "1.16.47-beta-20250807-110715-19ad6b43",
30
- "@abtnode/logger": "1.16.47-beta-20250807-110715-19ad6b43",
31
- "@abtnode/models": "1.16.47-beta-20250807-110715-19ad6b43",
32
- "@abtnode/queue": "1.16.47-beta-20250807-110715-19ad6b43",
33
- "@abtnode/rbac": "1.16.47-beta-20250807-110715-19ad6b43",
34
- "@abtnode/router-provider": "1.16.47-beta-20250807-110715-19ad6b43",
35
- "@abtnode/static-server": "1.16.47-beta-20250807-110715-19ad6b43",
36
- "@abtnode/timemachine": "1.16.47-beta-20250807-110715-19ad6b43",
37
- "@abtnode/util": "1.16.47-beta-20250807-110715-19ad6b43",
38
- "@aigne/aigne-hub": "^0.4.5",
22
+ "@abtnode/analytics": "1.16.47",
23
+ "@abtnode/auth": "1.16.47",
24
+ "@abtnode/certificate-manager": "1.16.47",
25
+ "@abtnode/client": "1.16.47",
26
+ "@abtnode/constant": "1.16.47",
27
+ "@abtnode/cron": "1.16.47",
28
+ "@abtnode/db-cache": "1.16.47",
29
+ "@abtnode/docker-utils": "1.16.47",
30
+ "@abtnode/logger": "1.16.47",
31
+ "@abtnode/models": "1.16.47",
32
+ "@abtnode/queue": "1.16.47",
33
+ "@abtnode/rbac": "1.16.47",
34
+ "@abtnode/router-provider": "1.16.47",
35
+ "@abtnode/static-server": "1.16.47",
36
+ "@abtnode/timemachine": "1.16.47",
37
+ "@abtnode/util": "1.16.47",
38
+ "@aigne/aigne-hub": "^0.4.6",
39
39
  "@arcblock/did": "1.21.2",
40
40
  "@arcblock/did-connect-js": "1.21.2",
41
41
  "@arcblock/did-ext": "1.21.2",
@@ -46,15 +46,15 @@
46
46
  "@arcblock/pm2-events": "^0.0.5",
47
47
  "@arcblock/validator": "1.21.2",
48
48
  "@arcblock/vc": "1.21.2",
49
- "@blocklet/constant": "1.16.47-beta-20250807-110715-19ad6b43",
50
- "@blocklet/did-space-js": "^1.1.13",
51
- "@blocklet/env": "1.16.47-beta-20250807-110715-19ad6b43",
49
+ "@blocklet/constant": "1.16.47",
50
+ "@blocklet/did-space-js": "^1.1.14",
51
+ "@blocklet/env": "1.16.47",
52
52
  "@blocklet/error": "^0.2.5",
53
- "@blocklet/meta": "1.16.47-beta-20250807-110715-19ad6b43",
54
- "@blocklet/resolver": "1.16.47-beta-20250807-110715-19ad6b43",
55
- "@blocklet/sdk": "1.16.47-beta-20250807-110715-19ad6b43",
56
- "@blocklet/store": "1.16.47-beta-20250807-110715-19ad6b43",
57
- "@blocklet/theme": "^3.0.42",
53
+ "@blocklet/meta": "1.16.47",
54
+ "@blocklet/resolver": "1.16.47",
55
+ "@blocklet/sdk": "1.16.47",
56
+ "@blocklet/store": "1.16.47",
57
+ "@blocklet/theme": "^3.1.3",
58
58
  "@fidm/x509": "^1.2.1",
59
59
  "@ocap/mcrypto": "1.21.2",
60
60
  "@ocap/util": "1.21.2",
@@ -118,5 +118,5 @@
118
118
  "jest": "^29.7.0",
119
119
  "unzipper": "^0.10.11"
120
120
  },
121
- "gitHead": "639aa367b25d6885e38cba99f73d753b2831393d"
121
+ "gitHead": "02eecfdabe8acf7a10b0cc897958667777d64f79"
122
122
  }