@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.
- package/lib/commands/blocklet/bundle/bundlers/screenshots.js +1 -1
- package/lib/commands/blocklet/deploy.js +2 -2
- package/lib/commands/server/command.js +0 -8
- package/lib/commands/server/info.js +1 -1
- package/lib/commands/server/init.js +1 -2
- package/lib/commands/server/start.js +26 -14
- package/lib/commands/server/stop.js +1 -1
- package/lib/manager/process.js +1 -1
- package/lib/port.js +2 -0
- package/lib/process/daemon.js +16 -16
- package/lib/process/event-hub.js +24 -0
- package/lib/process/service.js +8 -0
- package/lib/util/exit-when-server-stopped.js +1 -1
- package/lib/util/index.js +32 -15
- package/package.json +25 -25
- package/lib/commands/server/rescue.js +0 -71
- package/lib/util/get-service-instance-number.js +0 -12
|
@@ -12,7 +12,7 @@ class ScreenshotsBundler {
|
|
|
12
12
|
* @param {{
|
|
13
13
|
* blockletDir: string,
|
|
14
14
|
* bundleDir: string,
|
|
15
|
-
* meta: import('@
|
|
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('@
|
|
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('@
|
|
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:
|
|
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
|
|
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
|
-
|
|
260
|
-
|
|
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',
|
|
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
|
|
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
|
-
|
|
642
|
-
|
|
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 {
|
package/lib/manager/process.js
CHANGED
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) => {
|
package/lib/process/daemon.js
CHANGED
|
@@ -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;
|
package/lib/process/service.js
CHANGED
|
@@ -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();
|
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
|
|
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
|
|
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 =
|
|
225
|
-
const port =
|
|
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
|
|
240
|
+
// 因为 pm2 的 bug, 子进程会继承 namespace 和众多参数, 所以这里的 namespace 会给 blocklets 用
|
|
241
|
+
namespace: 'blocklets',
|
|
233
242
|
name: PROCESS_NAME_EVENT_HUB,
|
|
234
|
-
script:
|
|
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
|
-
|
|
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
|
|
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-
|
|
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-
|
|
39
|
-
"@abtnode/
|
|
40
|
-
"@abtnode/
|
|
41
|
-
"@abtnode/
|
|
42
|
-
"@abtnode/
|
|
43
|
-
"@abtnode/
|
|
44
|
-
"@abtnode/
|
|
45
|
-
"@abtnode/
|
|
46
|
-
"@abtnode/
|
|
47
|
-
"@
|
|
48
|
-
"@arcblock/
|
|
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.
|
|
52
|
-
"@arcblock/ws": "1.
|
|
53
|
-
"@blocklet/constant": "1.16.49-beta-
|
|
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-
|
|
57
|
-
"@blocklet/meta": "1.16.49-beta-
|
|
58
|
-
"@blocklet/resolver": "1.16.49-beta-
|
|
59
|
-
"@blocklet/
|
|
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.
|
|
62
|
-
"@ocap/mcrypto": "1.
|
|
63
|
-
"@ocap/util": "1.
|
|
64
|
-
"@ocap/wallet": "1.
|
|
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": "
|
|
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
|
-
};
|