@blocklet/cli 1.16.49-beta-20250815-032308-7bcf0b85 → 1.16.49-beta-20250821-102221-1b7283d6

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.
@@ -12,7 +12,7 @@ class ScreenshotsBundler {
12
12
  * @param {{
13
13
  * blockletDir: string,
14
14
  * bundleDir: string,
15
- * meta: import('@abtnode/client').BlockletMeta
15
+ * meta: import('@blocklet/server-js').BlockletMeta
16
16
  * }} { blockletDir, bundleDir, meta }
17
17
  * @memberof ScreenshotsBundler
18
18
  */
@@ -8,7 +8,7 @@ const chalk = require('chalk');
8
8
  const { joinURL } = require('ufo');
9
9
 
10
10
  const { isValid: isValidDid, toAddress } = require('@arcblock/did');
11
- const Client = require('@abtnode/client');
11
+ const Client = require('@blocklet/server-js');
12
12
  const hashFiles = require('@abtnode/util/lib/hash-files');
13
13
  const { default: axios } = require('axios');
14
14
  const validateBlockletEntry = require('@blocklet/meta/lib/entry');
@@ -451,7 +451,7 @@ const verifyEndpoint = async (opts) => {
451
451
  opts.connectEndpoint = opts.endpoint;
452
452
  opts.endpoint = endpoint;
453
453
 
454
- if (appPid) {
454
+ if (appPid && !opts.appDid) {
455
455
  opts.appDid = appPid;
456
456
  }
457
457
 
@@ -17,7 +17,6 @@ const cleanup = require('./cleanup');
17
17
  const logs = require('./logs');
18
18
  const status = require('./status');
19
19
  const upgrade = require('./upgrade');
20
- const rescue = require('./rescue');
21
20
  const migrate = require('./migrate');
22
21
  const { printVersionTip } = require('../../util');
23
22
 
@@ -107,13 +106,6 @@ module.exports = (parentCommand = '') => {
107
106
  .description('Stop Blocklet Server and blocklets')
108
107
  .action(parseOptions(stop.run));
109
108
 
110
- program
111
- .command('rescue')
112
- .option('--stopped-after <datetime>', 'Only start blocklets that are stopped after the specified time')
113
- .option('-f --force', 'Force start all blocklets, even if they are already running', false)
114
- .description('Start all blocklets in current running server')
115
- .action(parseOptions(rescue.run));
116
-
117
109
  program
118
110
  .command('info')
119
111
  .option('-C --clipboard', 'Automatically copy environment information to clipboard', false)
@@ -67,7 +67,7 @@ exports.run = ({ clipboard }) => {
67
67
  const correct = await ip.isDnsIpMappingCorrect(config.node.did);
68
68
 
69
69
  /**
70
- * @type {{node: import('@abtnode/client')}}
70
+ * @type {{node: import('@blocklet/server-js')}}
71
71
  */
72
72
  const { node } = await getNode({ dir: process.cwd() });
73
73
 
@@ -20,7 +20,6 @@ const {
20
20
  MAX_UPLOAD_FILE_SIZE,
21
21
  NODE_MODES,
22
22
  DEFAULT_DID_REGISTRY,
23
- PROXY_MAX_MEM_LIMIT_IN_MB,
24
23
  DEFAULT_DID_DOMAIN,
25
24
  DEFAULT_SLP_DOMAIN,
26
25
  } = require('@abtnode/constant');
@@ -389,7 +388,7 @@ exports.run = async ({
389
388
  },
390
389
  runtimeConfig: {
391
390
  daemonMaxMemoryLimit: Math.floor(daemonMaxMemoryLimit * 1024),
392
- proxyMaxMemoryLimit: PROXY_MAX_MEM_LIMIT_IN_MB,
391
+ proxyMaxMemoryLimit: BLOCKLET_MAX_MEM_LIMIT_IN_MB,
393
392
  blockletMaxMemoryLimit: Math.floor(blockletMaxMemoryLimit * 1024),
394
393
  },
395
394
  didRegistry: (process.env.ABT_NODE_DID_REGISTRY || didRegistry || DEFAULT_DID_REGISTRY).trim(),
@@ -12,7 +12,7 @@ const get = require('lodash/get');
12
12
  const isEqual = require('lodash/isEqual');
13
13
  const isObject = require('lodash/isObject');
14
14
  const readLastLines = require('read-last-lines');
15
- const pm2 = require('@abtnode/util/lib/async-pm2');
15
+ const pm2 = require('@abtnode/util/lib/pm2/async-pm2');
16
16
  const { isInServerlessMode } = require('@abtnode/util/lib/serverless');
17
17
  const ensureEndpointHealthy = require('@abtnode/util/lib/ensure-endpoint-healthy');
18
18
  const { runMigrationScripts, runSchemaMigrations } = require('@abtnode/core/lib/migrations');
@@ -30,7 +30,6 @@ const {
30
30
  CONFIG_FOLDER_NAME_OLD,
31
31
  MAX_UPLOAD_FILE_SIZE,
32
32
  DAEMON_MAX_MEM_LIMIT_IN_MB,
33
- PROXY_MAX_MEM_LIMIT_IN_MB,
34
33
  BLOCKLET_MAX_MEM_LIMIT_IN_MB,
35
34
  EVENTS,
36
35
  NODE_MODES,
@@ -41,11 +40,12 @@ const {
41
40
  const { canUseFileSystemIsolateApi, SAFE_NODE_VERSION } = require('@abtnode/util/lib/security');
42
41
  const { ensureDockerRedis } = require('@abtnode/core/lib/util/docker/ensure-docker-redis');
43
42
  const { ensureDockerPostgres } = require('@abtnode/core/lib/util/docker/ensure-docker-postgres');
43
+ const { getDaemonInstanceCount, getServiceInstanceCount } = require('@abtnode/util/lib/pm2/get-instance-number');
44
+ const { pm2StartOrReload } = require('@abtnode/util/lib/pm2/pm2-start-or-reload');
44
45
 
45
46
  const { version } = require('../../../package.json');
46
47
  const debug = require('../../debug')('start');
47
48
  const util = require('../../util');
48
- const getServiceInstanceNumber = require('../../util/get-service-instance-number');
49
49
  const {
50
50
  getConfigFileFromAncestors,
51
51
  getRunningConfigFile,
@@ -246,7 +246,7 @@ const startService = async (logDir, maxMemoryRestart, environments) => {
246
246
 
247
247
  try {
248
248
  await wrapSpinner('Starting blocklet service...', async () => {
249
- await pm2.startAsync({
249
+ await pm2StartOrReload({
250
250
  namespace: 'daemon',
251
251
  name: PROCESS_NAME_SERVICE,
252
252
  script: './lib/process/service.js',
@@ -254,18 +254,20 @@ const startService = async (logDir, maxMemoryRestart, environments) => {
254
254
  output: path.join(logDir, 'service.stdout.log'),
255
255
  error: path.join(logDir, 'service.stderr.log'),
256
256
  cwd: getCliCwd(),
257
- wait_ready: true,
258
257
  max_restarts: 3,
259
- listen_timeout: 3000,
260
- pmx: false,
258
+ wait_ready: true,
259
+ listen_timeout: 40_000,
260
+ kill_timeout: 10_000,
261
+ execMode: 'cluster',
262
+ shutdown_with_message: true,
263
+ instances: getServiceInstanceCount(),
261
264
  time: true,
265
+ pmx: false,
262
266
  env: {
263
267
  ...environments,
264
268
  ABT_NODE_SERVICE_PORT: servicePort,
265
269
  },
266
- execMode: 'cluster',
267
270
  mergeLogs: true,
268
- instances: getServiceInstanceNumber(),
269
271
  interpreter_args: environments.ABT_NODE_KERNEL_MODE === ABT_NODE_KERNEL_OR_BLOCKLET_MODE.PERFORMANT ? [] : ['--optimize_for_size'],
270
272
  });
271
273
 
@@ -410,6 +412,10 @@ const exec = async ({ workingDir, config, dataDir, mode, updateDb, forceIntranet
410
412
  process.env.ABT_NODE_CACHE_SQLITE_PATH = path.join(dataDir, 'core', 'db-cache.db');
411
413
  }
412
414
 
415
+ if (!process.env.ABT_NODE_DATA_DIR) {
416
+ process.env.ABT_NODE_DATA_DIR = dataDir;
417
+ }
418
+
413
419
  const redisUrl = await ensureDockerRedis();
414
420
  if (redisUrl) {
415
421
  process.env.ABT_NODE_CACHE_REDIS_URL = redisUrl;
@@ -426,7 +432,7 @@ const exec = async ({ workingDir, config, dataDir, mode, updateDb, forceIntranet
426
432
 
427
433
  const configFile = await getConfigFile(workingDir);
428
434
 
429
- const proxyMaxMemoryLimit = get(config, 'node.runtimeConfig.proxyMaxMemoryLimit', PROXY_MAX_MEM_LIMIT_IN_MB);
435
+ const proxyMaxMemoryLimit = get(config, 'node.runtimeConfig.proxyMaxMemoryLimit', BLOCKLET_MAX_MEM_LIMIT_IN_MB);
430
436
 
431
437
  // 如果日志目录不存在,pm2 会启动可能会失败, 测试发现 docker 里的 Ubuntu 18.04.4 LTS 系统会失败,
432
438
  // MAC OS 下正常,但是没搞明白为什么
@@ -437,7 +443,7 @@ const exec = async ({ workingDir, config, dataDir, mode, updateDb, forceIntranet
437
443
  const { node, getBaseUrls, publishEvent, wallet } = await nodeLib.getNode({ dir: workingDir });
438
444
 
439
445
  // start event-hub
440
- const eventHubPort = await startEventHub(logDir, proxyMaxMemoryLimit);
446
+ const [eventHubPort, pm2EventHubPort] = await startEventHub(logDir, proxyMaxMemoryLimit, config.node.sk);
441
447
 
442
448
  return new Promise((resolve) => {
443
449
  node.onReady(async () => {
@@ -600,6 +606,7 @@ const exec = async ({ workingDir, config, dataDir, mode, updateDb, forceIntranet
600
606
  ABT_NODE_JOB_NAME: process.env.ABT_NODE_JOB_NAME || '', // used to trigger log analyzing
601
607
  ABT_NODE_BINARY_NAME,
602
608
  ABT_NODE_COMMAND_NAME,
609
+ ABT_NODE_EVENT_HTTP_PORT: pm2EventHubPort,
603
610
  BLOCKLET_SERVER_RUNNING_BEFORE: isRunning ? '1' : '',
604
611
  ABT_NODE_ENSURE_RUNNING_CHECK_INTERVAL: process.env.ABT_NODE_ENSURE_RUNNING_CHECK_INTERVAL,
605
612
  ABT_NODE_ENSURE_RUNNING_DEFERRED_TIME: process.env.ABT_NODE_ENSURE_RUNNING_DEFERRED_TIME,
@@ -628,7 +635,7 @@ const exec = async ({ workingDir, config, dataDir, mode, updateDb, forceIntranet
628
635
  // check localhost listening
629
636
  await wrapSpinner('Starting server daemon...', async () => {
630
637
  // start daemon
631
- await pm2.startAsync({
638
+ await pm2StartOrReload({
632
639
  namespace: 'daemon',
633
640
  name: PROCESS_NAME_DAEMON,
634
641
  script: './lib/process/daemon.js',
@@ -638,10 +645,15 @@ const exec = async ({ workingDir, config, dataDir, mode, updateDb, forceIntranet
638
645
  cwd: getCliCwd(),
639
646
  max_restarts: 3,
640
647
  wait_ready: true,
641
- listen_timeout: 3000,
642
- env: environments,
648
+ min_uptime: 15_000,
649
+ listen_timeout: 40_000,
650
+ kill_timeout: 10_000,
651
+ execMode: 'cluster',
652
+ shutdown_with_message: true,
653
+ instances: getDaemonInstanceCount(),
643
654
  time: true,
644
655
  pmx: false,
656
+ env: environments,
645
657
  interpreter_args:
646
658
  environments.ABT_NODE_KERNEL_MODE === ABT_NODE_KERNEL_OR_BLOCKLET_MODE.PERFORMANT
647
659
  ? []
@@ -4,7 +4,7 @@ const capitalize = require('lodash/capitalize');
4
4
  const { clearRouterByConfigKeyword, clearDockerContainer, checkDockerInstalled } = require('@abtnode/router-provider');
5
5
  const tryWithTimeout = require('@abtnode/util/lib/try-with-timeout');
6
6
  const sleep = require('@abtnode/util/lib/sleep');
7
- const pm2 = require('@abtnode/util/lib/async-pm2');
7
+ const pm2 = require('@abtnode/util/lib/pm2/async-pm2');
8
8
  const pAll = require('p-all');
9
9
 
10
10
  const {
@@ -1,5 +1,5 @@
1
1
  const path = require('path');
2
- const pm2 = require('@abtnode/util/lib/async-pm2');
2
+ const pm2 = require('@abtnode/util/lib/pm2/async-pm2');
3
3
 
4
4
  const { PROCESS_NAME_DAEMON } = require('@abtnode/constant');
5
5
 
package/lib/port.js CHANGED
@@ -3,6 +3,7 @@ const {
3
3
  PROCESS_NAME_UPDATER,
4
4
  PROCESS_NAME_SERVICE,
5
5
  PROCESS_NAME_EVENT_HUB,
6
+ PROCESS_NAME_PM2_EVENT_HUB,
6
7
  } = require('@abtnode/constant');
7
8
 
8
9
  const ports = {
@@ -10,6 +11,7 @@ const ports = {
10
11
  [PROCESS_NAME_UPDATER]: 40405,
11
12
  [PROCESS_NAME_SERVICE]: 40406,
12
13
  [PROCESS_NAME_EVENT_HUB]: 40407,
14
+ [PROCESS_NAME_PM2_EVENT_HUB]: 40411,
13
15
  };
14
16
 
15
17
  const getInternalPort = (processName) => {
@@ -1,6 +1,10 @@
1
1
  /* eslint-disable no-console */
2
2
  /* eslint-disable no-await-in-loop */
3
3
 
4
+ const { loadReloadEnv } = require('@abtnode/util/lib/pm2/pm2-start-or-reload');
5
+
6
+ loadReloadEnv();
7
+
4
8
  if (!process.env.NODE_ENV) {
5
9
  process.env.NODE_ENV = 'production';
6
10
  }
@@ -25,12 +29,13 @@ const ABTNode = require('@abtnode/core');
25
29
 
26
30
  const getNodeWallet = require('@abtnode/util/lib/get-app-wallet');
27
31
 
28
- const { getDisplayName } = require('@blocklet/meta/lib/util');
29
-
30
32
  const { SERVER_STATUS } = require('@abtnode/constant');
31
33
 
32
34
  const createServer = require('@abtnode/webapp/blocklet'); // eslint-disable-line
33
35
 
36
+ const { setupGracefulShutdown } = require('@abtnode/util/lib/pm2/setup-graceful-shutdown');
37
+ const ensureBlockletRunning = require('@abtnode/core/lib/blocklet/manager/ensure-blocklet-running');
38
+
34
39
  const wallet = getNodeWallet(process.env.ABT_NODE_SK);
35
40
  const dataDir = process.env.ABT_NODE_DATA_DIR;
36
41
 
@@ -47,18 +52,6 @@ const node = ABTNode({
47
52
  node.collectorPath = path.dirname(require.resolve('@blocklet/form-collector'));
48
53
  node.themeBuilderPath = path.dirname(require.resolve('@blocklet/theme-builder'));
49
54
 
50
- const syncComponentStatus = async () => {
51
- const apps = await node.getBlocklets({ includeRuntimeInfo: false });
52
- for (let i = 0; i < apps.length; i++) {
53
- const app = apps[i];
54
- try {
55
- await node.syncBlockletStatus(app.meta.did, { forceSync: true });
56
- } catch (err) {
57
- logger.error(`Blocklet ${getDisplayName(app)} status sync failed: ${err.message}`);
58
- }
59
- }
60
- };
61
-
62
55
  logger.info('Waiting for Blocklet Server Daemon instance created');
63
56
  node.onReady(async () => {
64
57
  logger.info('Blocklet Server Daemon instance was created');
@@ -74,8 +67,11 @@ node.onReady(async () => {
74
67
  logger.info('Service gateway was restarted');
75
68
 
76
69
  const server = createServer(node);
70
+ setupGracefulShutdown(server);
71
+
77
72
  server.listen(process.env.ABT_NODE_PORT, '0.0.0.0', async (err) => {
78
73
  if (err) throw err;
74
+ process.send?.('ready');
79
75
  console.info(`> Blocklet Server Daemon ready on ${process.env.ABT_NODE_PORT}`);
80
76
 
81
77
  // Should resume upgrading if we are in process
@@ -98,12 +94,16 @@ node.onReady(async () => {
98
94
  await node.updateNodeStatus(SERVER_STATUS.RUNNING);
99
95
  if (runningBefore) {
100
96
  logger.info('> Blocklet Server is restarted from running before');
97
+ // 如果之前是运行中, 直接跳过快速重启检查
98
+ ensureBlockletRunning.whenCycleCheck = true;
99
+ } else {
100
+ logger.info('> Blocklet Server is stopped from running before');
101
101
  }
102
-
103
- await syncComponentStatus();
104
102
  }
105
103
  } catch (e) {
106
104
  console.error('> Blocklet Server failed to restart running blocklets', e);
105
+ } finally {
106
+ ensureBlockletRunning.canRunEnsureBlockletRunning = true;
107
107
  }
108
108
 
109
109
  try {
@@ -0,0 +1,24 @@
1
+ /* eslint-disable no-console */
2
+ const { setupGracefulShutdown } = require('@abtnode/util/lib/pm2/setup-graceful-shutdown');
3
+ const server = require('@arcblock/event-hub/lib/server-abtnode.js');
4
+ const pm2 = require('@abtnode/util/lib/pm2/async-pm2');
5
+ const md5 = require('@abtnode/util/lib/md5');
6
+
7
+ setupGracefulShutdown(server);
8
+
9
+ const pm2Pwd = md5(`${process.env.ABT_NODE_SK}-fetch-pm2`);
10
+
11
+ server.register(
12
+ 'pm2/start',
13
+ async (payload) => {
14
+ const { pm2Config, pwd } = payload || {};
15
+ if (!pwd || pwd !== pm2Pwd) {
16
+ return { ok: false, error: 'unauthorized start the blocklet' };
17
+ }
18
+ await pm2.startAsync(pm2Config);
19
+ return { ok: true, data: 'ok' };
20
+ },
21
+ { authRequired: false }
22
+ );
23
+
24
+ module.exports = server;
@@ -1,6 +1,10 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
3
 
4
+ const { loadReloadEnv } = require('@abtnode/util/lib/pm2/pm2-start-or-reload');
5
+
6
+ loadReloadEnv();
7
+
4
8
  if (!process.env.NODE_ENV) {
5
9
  process.env.NODE_ENV = 'production';
6
10
  }
@@ -20,6 +24,7 @@ const ABTNode = require('@abtnode/core');
20
24
  const getNodeWallet = require('@abtnode/util/lib/get-app-wallet');
21
25
 
22
26
  const createServer = require('@abtnode/blocklet-services');
27
+ const { setupGracefulShutdown } = require('@abtnode/util/lib/pm2/setup-graceful-shutdown');
23
28
 
24
29
  const { version } = require('../../package.json');
25
30
 
@@ -60,12 +65,15 @@ const notifyServerVersionToApps = async (server) => {
60
65
 
61
66
  node.onReady(() => {
62
67
  const server = createServer(node);
68
+ setupGracefulShutdown(server);
63
69
 
64
70
  server.listen(port, '0.0.0.0', async (err) => {
65
71
  if (err) throw err;
66
72
  // eslint-disable-next-line
67
73
  console.log(`> Blocklet Service ready on ${port}`);
68
74
 
75
+ process.send?.('ready');
76
+
69
77
  try {
70
78
  if (dataDir && fs.existsSync(path.join(dataDir, 'start.lock')) === false) {
71
79
  const nodeInfo = await node.getNodeInfo();
@@ -1,4 +1,4 @@
1
- const pm2 = require('@abtnode/util/lib/async-pm2');
1
+ const pm2 = require('@abtnode/util/lib/pm2/async-pm2');
2
2
  const { PROCESS_NAME_DAEMON } = require('@abtnode/constant');
3
3
 
4
4
  const exitWhenServerStopped = () => {
package/lib/util/index.js CHANGED
@@ -9,14 +9,12 @@ const { filesize } = require('filesize');
9
9
  const fs = require('fs-extra');
10
10
  const git = require('git-rev-sync');
11
11
  const uniq = require('lodash/uniq');
12
- const portUsed = require('port-used');
13
12
  const pRetry = require('p-retry');
14
13
  const { joinURL } = require('ufo');
15
14
  const getNodeWallet = require('@abtnode/util/lib/get-app-wallet');
16
15
  const isDocker = require('@abtnode/util/lib/is-docker');
17
16
  const isGitpod = require('@abtnode/util/lib/is-gitpod');
18
- const ensureListening = require('@abtnode/util/lib/ensure-listening');
19
- const pm2 = require('@abtnode/util/lib/async-pm2');
17
+ const pm2 = require('@abtnode/util/lib/pm2/async-pm2');
20
18
  const getIP = require('@abtnode/util/lib/get-ip');
21
19
  const sleep = require('@abtnode/util/lib/sleep');
22
20
  const axios = require('@abtnode/util/lib/axios');
@@ -24,22 +22,26 @@ const cloud = require('@abtnode/util/lib/cloud');
24
22
  const { formatError } = require('@blocklet/error');
25
23
  const { updateServerDocument } = require('@abtnode/util/lib/did-document');
26
24
  const { getProvider } = require('@abtnode/router-provider');
25
+ const portUsed = require('port-used');
27
26
  const { decideHttpPort, decideHttpsPort } = require('@abtnode/router-provider/lib/util');
28
- const tryWithTimeout = require('@abtnode/util/lib/try-with-timeout');
29
27
  const codespaces = require('@abtnode/util/lib/codespaces');
28
+ const ensureEndpointHealthy = require('@abtnode/util/lib/ensure-endpoint-healthy');
29
+ const { isProcessRunningByPm2 } = require('@abtnode/util/lib/pm2/pm2-start-or-reload');
30
+
30
31
  const {
31
32
  PROCESS_NAME_EVENT_HUB,
32
- PROXY_MAX_MEM_LIMIT_IN_MB,
33
33
  DEFAULT_DESCRIPTION,
34
34
  DEFAULT_HTTP_PORT,
35
35
  NODE_MODES,
36
36
  DEFAULT_HTTPS_PORT,
37
+ PROCESS_NAME_PM2_EVENT_HUB,
38
+ BLOCKLET_MAX_MEM_LIMIT_IN_MB,
37
39
  } = require('@abtnode/constant');
38
40
  const gitUserName = require('git-user-name');
39
41
 
40
42
  const pkg = require('../../package.json');
41
43
  const { symbols, wrapSpinner } = require('../ui');
42
- const { getInternalPort: getPort } = require('../port');
44
+ const { getInternalPort } = require('../port');
43
45
  const debug = require('../debug')('util');
44
46
  const getCLIBinaryName = require('./get-cli-binary-name');
45
47
  const printError = require('./print-error');
@@ -115,6 +117,11 @@ const checkRoutingProvider = async (info, { configDir } = {}) => {
115
117
  return true;
116
118
  }
117
119
 
120
+ const isHasRunning = await isProcessRunningByPm2(PROCESS_NAME_EVENT_HUB);
121
+ if (isHasRunning) {
122
+ return true;
123
+ }
124
+
118
125
  const result = await Provider.check({ configDir });
119
126
  if (!result.available) {
120
127
  printError(result.error);
@@ -221,31 +228,41 @@ const getGitHash = (dir) => git.long(dir);
221
228
 
222
229
  const getCliCwd = () => path.dirname(path.dirname(__dirname));
223
230
 
224
- const startEventHub = async (logDir, maxMemoryRestart = PROXY_MAX_MEM_LIMIT_IN_MB) => {
225
- const port = getPort(PROCESS_NAME_EVENT_HUB);
231
+ const startEventHub = async (logDir, maxMemoryRestart = BLOCKLET_MAX_MEM_LIMIT_IN_MB, ABT_NODE_SK = '') => {
232
+ const port = getInternalPort(PROCESS_NAME_EVENT_HUB);
233
+ const pm2EventHubPort = getInternalPort(PROCESS_NAME_PM2_EVENT_HUB);
226
234
  debug('start event hub', { port });
227
235
 
228
236
  const tryStartEventHub = async () => {
229
237
  try {
230
238
  await wrapSpinner('Starting event hub...', async () => {
231
239
  await pm2.startAsync({
232
- namespace: 'daemon',
240
+ // 因为 pm2 的 bug, 子进程会继承 namespace 和众多参数, 所以这里的 namespace 会给 blocklets 用
241
+ namespace: 'blocklets',
233
242
  name: PROCESS_NAME_EVENT_HUB,
234
- script: require.resolve('@arcblock/event-hub/lib/server-abtnode.js'),
243
+ script: './lib/process/event-hub.js',
235
244
  max_memory_restart: `${maxMemoryRestart}M`,
236
245
  output: path.join(logDir, 'event.output.log'),
237
246
  error: path.join(logDir, 'event.error.log'),
238
- cwd: getCliCwd(),
239
- wait_ready: true,
240
- max_restarts: 3,
247
+ wait_ready: false,
241
248
  listen_timeout: 3000,
249
+ exec_mode: 'cluster',
250
+ max_restarts: 3,
251
+ cwd: getCliCwd(),
242
252
  time: true,
243
253
  pmx: false,
244
254
  env: {
245
255
  ABT_NODE_EVENT_PORT: port,
256
+ ABT_NODE_EVENT_HTTP_PORT: pm2EventHubPort,
257
+ ABT_NODE_SK,
246
258
  },
247
259
  });
248
- await tryWithTimeout(() => ensureListening(port), 10000);
260
+ await ensureEndpointHealthy({
261
+ protocol: 'tcp',
262
+ port,
263
+ timeout: 5 * 60 * 1000, // wait up to 5 minutes
264
+ minConsecutiveTime: 2000,
265
+ });
249
266
  });
250
267
 
251
268
  process.env.ABT_NODE_EVENT_PORT = port;
@@ -257,7 +274,7 @@ const startEventHub = async (logDir, maxMemoryRestart = PROXY_MAX_MEM_LIMIT_IN_M
257
274
 
258
275
  await tryStartEventHub();
259
276
 
260
- return port;
277
+ return [port, pm2EventHubPort];
261
278
  };
262
279
 
263
280
  const killPm2Process = async (name) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blocklet/cli",
3
- "version": "1.16.49-beta-20250815-032308-7bcf0b85",
3
+ "version": "1.16.49-beta-20250821-102221-1b7283d6",
4
4
  "description": "Command line tools to manage Blocklet Server",
5
5
  "homepage": "https://github.com/ArcBlock/blocklet-server#readme",
6
6
  "bin": {
@@ -35,33 +35,33 @@
35
35
  "url": "https://github.com/ArcBlock/blocklet-server/issues"
36
36
  },
37
37
  "dependencies": {
38
- "@abtnode/blocklet-services": "1.16.49-beta-20250815-032308-7bcf0b85",
39
- "@abtnode/client": "1.16.49-beta-20250815-032308-7bcf0b85",
40
- "@abtnode/constant": "1.16.49-beta-20250815-032308-7bcf0b85",
41
- "@abtnode/core": "1.16.49-beta-20250815-032308-7bcf0b85",
42
- "@abtnode/db-cache": "1.16.49-beta-20250815-032308-7bcf0b85",
43
- "@abtnode/logger": "1.16.49-beta-20250815-032308-7bcf0b85",
44
- "@abtnode/models": "1.16.49-beta-20250815-032308-7bcf0b85",
45
- "@abtnode/router-provider": "1.16.49-beta-20250815-032308-7bcf0b85",
46
- "@abtnode/util": "1.16.49-beta-20250815-032308-7bcf0b85",
47
- "@abtnode/webapp": "1.16.49-beta-20250815-032308-7bcf0b85",
48
- "@arcblock/did": "1.21.2",
49
- "@arcblock/event-hub": "1.21.2",
38
+ "@abtnode/blocklet-services": "1.16.49-beta-20250821-102221-1b7283d6",
39
+ "@abtnode/constant": "1.16.49-beta-20250821-102221-1b7283d6",
40
+ "@abtnode/core": "1.16.49-beta-20250821-102221-1b7283d6",
41
+ "@abtnode/db-cache": "1.16.49-beta-20250821-102221-1b7283d6",
42
+ "@abtnode/logger": "1.16.49-beta-20250821-102221-1b7283d6",
43
+ "@abtnode/models": "1.16.49-beta-20250821-102221-1b7283d6",
44
+ "@abtnode/router-provider": "1.16.49-beta-20250821-102221-1b7283d6",
45
+ "@abtnode/util": "1.16.49-beta-20250821-102221-1b7283d6",
46
+ "@abtnode/webapp": "1.16.49-beta-20250821-102221-1b7283d6",
47
+ "@arcblock/did": "1.22.2",
48
+ "@arcblock/event-hub": "1.22.2",
50
49
  "@arcblock/ipfs-only-hash": "^0.0.2",
51
- "@arcblock/jwt": "1.21.2",
52
- "@arcblock/ws": "1.21.3",
53
- "@blocklet/constant": "1.16.49-beta-20250815-032308-7bcf0b85",
50
+ "@arcblock/jwt": "1.22.2",
51
+ "@arcblock/ws": "1.22.2",
52
+ "@blocklet/constant": "1.16.49-beta-20250821-102221-1b7283d6",
54
53
  "@blocklet/error": "^0.2.5",
55
54
  "@blocklet/form-collector": "^0.1.8",
56
- "@blocklet/images": "1.16.49-beta-20250815-032308-7bcf0b85",
57
- "@blocklet/meta": "1.16.49-beta-20250815-032308-7bcf0b85",
58
- "@blocklet/resolver": "1.16.49-beta-20250815-032308-7bcf0b85",
59
- "@blocklet/store": "1.16.49-beta-20250815-032308-7bcf0b85",
55
+ "@blocklet/images": "1.16.49-beta-20250821-102221-1b7283d6",
56
+ "@blocklet/meta": "1.16.49-beta-20250821-102221-1b7283d6",
57
+ "@blocklet/resolver": "1.16.49-beta-20250821-102221-1b7283d6",
58
+ "@blocklet/server-js": "1.16.49-beta-20250821-102221-1b7283d6",
59
+ "@blocklet/store": "1.16.49-beta-20250821-102221-1b7283d6",
60
60
  "@blocklet/theme-builder": "^0.4.6",
61
- "@ocap/client": "1.21.2",
62
- "@ocap/mcrypto": "1.21.2",
63
- "@ocap/util": "1.21.2",
64
- "@ocap/wallet": "1.21.2",
61
+ "@ocap/client": "1.22.2",
62
+ "@ocap/mcrypto": "1.22.2",
63
+ "@ocap/util": "1.22.2",
64
+ "@ocap/wallet": "1.22.2",
65
65
  "@vercel/ncc": "^0.38.3",
66
66
  "archiver": "^7.0.1",
67
67
  "async": "^3.2.4",
@@ -154,7 +154,7 @@
154
154
  "engines": {
155
155
  "node": ">=14"
156
156
  },
157
- "gitHead": "75dd236eb42d14a5093c1364e51625412aa91790",
157
+ "gitHead": "4fdd3b0cfb87b45ff8c0d539f83c3ddcbd71465b",
158
158
  "devDependencies": {
159
159
  "@types/fs-extra": "^11.0.4",
160
160
  "@types/jest": "^29.5.13"
@@ -1,71 +0,0 @@
1
- /* eslint-disable no-await-in-loop */
2
- /* eslint-disable no-continue */
3
-
4
- const trim = require('lodash/trim');
5
- const { BLOCKLET_MODES, BlockletStatus } = require('@blocklet/constant');
6
-
7
- const { getDisplayName } = require('@blocklet/meta/lib/util');
8
- const { printError, printSuccess, printWarning, printInfo } = require('../../util');
9
- const { getNode } = require('../../node');
10
- const { checkRunning } = require('../../manager');
11
- const { wrapSpinner } = require('../../ui');
12
-
13
- const isAfter = (t1, t2) => new Date(t1).getTime() >= new Date(t2).getTime();
14
-
15
- exports.run = async ({ force = false, stoppedAfter }) => {
16
- const { node } = await getNode({ dir: process.cwd() });
17
-
18
- if (!trim(stoppedAfter) || !new Date(stoppedAfter).getTime()) {
19
- printError('Please provide a valid --stopped-after time');
20
- process.exit(1);
21
- }
22
-
23
- const isRunning = await checkRunning();
24
- if (!isRunning) {
25
- printWarning('Blocklet Server is not running!');
26
- process.exit(0);
27
- }
28
-
29
- node.onReady(async () => {
30
- let blocklets = [];
31
-
32
- blocklets = await node.getBlocklets({ includeRuntimeInfo: false });
33
-
34
- for (let i = 0; i < blocklets.length; i++) {
35
- const blocklet = blocklets[i];
36
- const title = getDisplayName(blocklet);
37
- if (blocklet.mode === BLOCKLET_MODES.DEVELOPMENT) {
38
- printInfo(`Skip development blocklet: ${title}`);
39
- continue;
40
- }
41
-
42
- if (blocklet.status === BlockletStatus.running && !force) {
43
- printInfo(`Skip running blocklet: ${title}`);
44
- continue;
45
- }
46
-
47
- let minStoppedAt = 0;
48
- blocklet.children.forEach((child) => {
49
- if (isAfter(child.stoppedAt, minStoppedAt)) {
50
- minStoppedAt = child.stoppedAt;
51
- }
52
- });
53
-
54
- if (!isAfter(minStoppedAt, stoppedAfter)) {
55
- printInfo(`Skip blocklet: ${title} because it was not stopped after ${stoppedAfter}`);
56
- continue;
57
- }
58
-
59
- try {
60
- await wrapSpinner(`Starting blocklet: ${title}`, async () => {
61
- await node.startBlocklet({ did: blocklet.appDid, checkHealthImmediately: true, throwOnError: true });
62
- });
63
- } catch (err) {
64
- printError(`Failed to start blocklet ${title}`, err.message);
65
- }
66
- }
67
-
68
- printSuccess('Done!');
69
- process.exit(0);
70
- });
71
- };
@@ -1,12 +0,0 @@
1
- const os = require('os');
2
-
3
- module.exports = () => {
4
- // unit: GB
5
- const memorySize = Math.floor(os.totalmem() / 1024 / 1024 / 1024) || 1;
6
-
7
- const cpuLength = os.cpus().length || 1;
8
-
9
- const customConfig = +process.env.ABT_NODE_MAX_CLUSTER_SIZE || Number.MAX_SAFE_INTEGER;
10
-
11
- return Math.max(Math.min(memorySize, cpuLength, customConfig), 1);
12
- };