@nmakarov/cli-toolkit 0.51.0 → 0.55.0
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/dist/cli-runner.cjs +23 -12
- package/dist/cli-runner.cjs.map +1 -1
- package/dist/cli-runner.js +23 -12
- package/dist/cli-runner.js.map +1 -1
- package/dist/deploy.cjs +234 -16
- package/dist/deploy.cjs.map +1 -1
- package/dist/deploy.js +221 -10
- package/dist/deploy.js.map +1 -1
- package/dist/index.cjs +246 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +231 -18
- package/dist/index.js.map +1 -1
- package/dist/init.cjs +14 -5
- package/dist/init.cjs.map +1 -1
- package/dist/init.js +14 -5
- package/dist/init.js.map +1 -1
- package/dist/tasks.cjs +10 -8
- package/dist/tasks.cjs.map +1 -1
- package/dist/tasks.js +10 -8
- package/dist/tasks.js.map +1 -1
- package/package.json +1 -1
- package/scripts/deploy/cli.js +5 -1
package/dist/index.cjs
CHANGED
|
@@ -1147,11 +1147,14 @@ __export(src_exports, {
|
|
|
1147
1147
|
ensureTasksRuntime: () => ensureTasksRuntime,
|
|
1148
1148
|
flushTaskIpcLogs: () => flushTaskIpcLogs,
|
|
1149
1149
|
getArgsInstance: () => getArgsInstance,
|
|
1150
|
+
getPm2Process: () => getPm2Process,
|
|
1150
1151
|
h: () => import_react5.createElement,
|
|
1151
1152
|
initServiceStructure: () => initServiceStructure,
|
|
1152
1153
|
installDeps: () => installDeps,
|
|
1153
1154
|
installOperatorShell: () => installOperatorShell,
|
|
1154
1155
|
ipcFileLogsTableNameForSourceResource: () => ipcFileLogsTableNameForSourceResource,
|
|
1156
|
+
isFreshOnline: () => isFreshOnline,
|
|
1157
|
+
isPidAlive: () => isPidAlive,
|
|
1155
1158
|
joiEdateType: () => joiEdateType,
|
|
1156
1159
|
joiStringArrayType: () => joiStringArrayType,
|
|
1157
1160
|
listAliveRunnerHeartbeats: () => listServicesRegistry,
|
|
@@ -1193,6 +1196,7 @@ __export(src_exports, {
|
|
|
1193
1196
|
resolveSteps: () => resolveSteps,
|
|
1194
1197
|
rollbackService: () => rollbackService,
|
|
1195
1198
|
run: () => run,
|
|
1199
|
+
runCapture: () => runCapture,
|
|
1196
1200
|
runNodeTaskScript: () => runNodeTaskScript,
|
|
1197
1201
|
runReleaseTests: () => runReleaseTests,
|
|
1198
1202
|
runRemoteCli: () => runRemoteCli,
|
|
@@ -1210,6 +1214,8 @@ __export(src_exports, {
|
|
|
1210
1214
|
showScreen: () => showScreen,
|
|
1211
1215
|
showWordGridScreen: () => showWordGridScreen,
|
|
1212
1216
|
sshRun: () => sshRun,
|
|
1217
|
+
startPm2: () => startPm2,
|
|
1218
|
+
stopPm2: () => stopPm2,
|
|
1213
1219
|
syncEnv: () => syncEnv,
|
|
1214
1220
|
taskHistoryInsertFromQueueRow: () => taskHistoryInsertFromQueueRow,
|
|
1215
1221
|
timeMatcher: () => timeMatcher,
|
|
@@ -1227,6 +1233,7 @@ __export(src_exports, {
|
|
|
1227
1233
|
useRef: () => import_react5.useRef,
|
|
1228
1234
|
useState: () => import_react5.useState,
|
|
1229
1235
|
waitForTaskResult: () => waitForTaskResult,
|
|
1236
|
+
waitPm2: () => waitPm2,
|
|
1230
1237
|
writeReleaseBuildInfo: () => writeReleaseBuildInfo
|
|
1231
1238
|
});
|
|
1232
1239
|
module.exports = __toCommonJS(src_exports);
|
|
@@ -5383,8 +5390,13 @@ function defineService(service) {
|
|
|
5383
5390
|
const pm2 = {
|
|
5384
5391
|
appName: service.name,
|
|
5385
5392
|
args: "",
|
|
5393
|
+
stopAllowance: 60,
|
|
5386
5394
|
...service.pm2
|
|
5387
5395
|
};
|
|
5396
|
+
if (pm2.killTimeout == null) {
|
|
5397
|
+
const stopSec = Number(pm2.stopAllowance);
|
|
5398
|
+
pm2.killTimeout = Number.isFinite(stopSec) && stopSec > 0 ? Math.floor(stopSec * 1e3) + 5e3 : 65e3;
|
|
5399
|
+
}
|
|
5388
5400
|
const nginx = service.nginx ? { siteName: service.name, ...service.nginx } : null;
|
|
5389
5401
|
return {
|
|
5390
5402
|
repoDirName: deriveRepoDirName(service.repoUrl),
|
|
@@ -5465,6 +5477,30 @@ function run(cmd, args, options = {}) {
|
|
|
5465
5477
|
function runShell(command, options = {}) {
|
|
5466
5478
|
return run("bash", ["-lc", command], options);
|
|
5467
5479
|
}
|
|
5480
|
+
function runCapture(cmd, args, options = {}) {
|
|
5481
|
+
const { cwd, env, logger, allowFail = false } = options;
|
|
5482
|
+
return new Promise((resolve3, reject) => {
|
|
5483
|
+
logger?.info?.(`$ ${cmd} ${args.join(" ")}${cwd ? ` (cwd=${cwd})` : ""}`);
|
|
5484
|
+
const child = (0, import_node_child_process.spawn)(cmd, args, {
|
|
5485
|
+
cwd,
|
|
5486
|
+
env: env ?? process.env,
|
|
5487
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
5488
|
+
});
|
|
5489
|
+
let stdout = "";
|
|
5490
|
+
let stderr = "";
|
|
5491
|
+
child.stdout?.on("data", (chunk) => {
|
|
5492
|
+
stdout += chunk.toString();
|
|
5493
|
+
});
|
|
5494
|
+
child.stderr?.on("data", (chunk) => {
|
|
5495
|
+
stderr += chunk.toString();
|
|
5496
|
+
});
|
|
5497
|
+
child.on("error", reject);
|
|
5498
|
+
child.on("close", (code) => {
|
|
5499
|
+
if (code === 0 || allowFail) resolve3({ stdout, stderr, code });
|
|
5500
|
+
else reject(new Error(`${cmd} exited with code ${code}${stderr ? `: ${stderr.trim()}` : ""}`));
|
|
5501
|
+
});
|
|
5502
|
+
});
|
|
5503
|
+
}
|
|
5468
5504
|
|
|
5469
5505
|
// src/deploy/log.js
|
|
5470
5506
|
var import_promises = require("fs/promises");
|
|
@@ -5682,7 +5718,7 @@ async function runReleaseTests(service, releasePath, paths, options = {}) {
|
|
|
5682
5718
|
// src/deploy/prune.js
|
|
5683
5719
|
var import_promises7 = require("fs/promises");
|
|
5684
5720
|
async function pruneReleases(service, paths, options = {}) {
|
|
5685
|
-
const { dryRun = false, logger = console } = options;
|
|
5721
|
+
const { dryRun = false, logger = console, protect = [] } = options;
|
|
5686
5722
|
const keep = service.keepReleases ?? 3;
|
|
5687
5723
|
const releases = await listReleases(paths);
|
|
5688
5724
|
let activeName = null;
|
|
@@ -5696,6 +5732,9 @@ async function pruneReleases(service, paths, options = {}) {
|
|
|
5696
5732
|
if (keepSet.size < keep) keepSet.add(rel.name);
|
|
5697
5733
|
}
|
|
5698
5734
|
if (activeName) keepSet.add(activeName);
|
|
5735
|
+
for (const name of protect) {
|
|
5736
|
+
if (name) keepSet.add(name);
|
|
5737
|
+
}
|
|
5699
5738
|
const toRemove = releases.filter((rel) => !keepSet.has(rel.name));
|
|
5700
5739
|
for (const rel of toRemove) {
|
|
5701
5740
|
if (dryRun) {
|
|
@@ -5709,14 +5748,139 @@ async function pruneReleases(service, paths, options = {}) {
|
|
|
5709
5748
|
}
|
|
5710
5749
|
|
|
5711
5750
|
// src/deploy/pm2.js
|
|
5751
|
+
function sleep(ms) {
|
|
5752
|
+
return new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
5753
|
+
}
|
|
5754
|
+
function isPidAlive(pid) {
|
|
5755
|
+
const n = Number(pid);
|
|
5756
|
+
if (!Number.isFinite(n) || n <= 0) return false;
|
|
5757
|
+
try {
|
|
5758
|
+
process.kill(n, 0);
|
|
5759
|
+
return true;
|
|
5760
|
+
} catch {
|
|
5761
|
+
return false;
|
|
5762
|
+
}
|
|
5763
|
+
}
|
|
5764
|
+
async function getPm2Process(appName, options = {}) {
|
|
5765
|
+
const { logger } = options;
|
|
5766
|
+
const { stdout } = await runCapture("bash", ["-lc", "pm2 jlist"], { logger });
|
|
5767
|
+
let list;
|
|
5768
|
+
try {
|
|
5769
|
+
list = JSON.parse(stdout || "[]");
|
|
5770
|
+
} catch (err) {
|
|
5771
|
+
throw new Error(`pm2 jlist: invalid JSON (${err?.message ?? err})`);
|
|
5772
|
+
}
|
|
5773
|
+
if (!Array.isArray(list)) return null;
|
|
5774
|
+
return list.find((p) => p?.name === appName) ?? null;
|
|
5775
|
+
}
|
|
5776
|
+
async function waitPm2(appName, predicate, options = {}) {
|
|
5777
|
+
const {
|
|
5778
|
+
timeoutMs = 65e3,
|
|
5779
|
+
pollMs = 500,
|
|
5780
|
+
dryRun = false,
|
|
5781
|
+
logger = console,
|
|
5782
|
+
label = "condition"
|
|
5783
|
+
} = options;
|
|
5784
|
+
if (dryRun) {
|
|
5785
|
+
logger.info?.(`[dryRun] would wait pm2 ${appName} for ${label}`);
|
|
5786
|
+
return null;
|
|
5787
|
+
}
|
|
5788
|
+
const deadline = Date.now() + timeoutMs;
|
|
5789
|
+
let lastStatus = "(unknown)";
|
|
5790
|
+
while (Date.now() < deadline) {
|
|
5791
|
+
const proc = await getPm2Process(appName, { logger });
|
|
5792
|
+
lastStatus = proc?.pm2_env?.status ?? "(missing)";
|
|
5793
|
+
if (predicate(proc)) return proc;
|
|
5794
|
+
await sleep(pollMs);
|
|
5795
|
+
}
|
|
5796
|
+
throw new Error(
|
|
5797
|
+
`pm2 wait timed out after ${timeoutMs}ms for ${appName} (${label}); last status=${lastStatus}`
|
|
5798
|
+
);
|
|
5799
|
+
}
|
|
5800
|
+
function isFreshOnline(proc, oldPid) {
|
|
5801
|
+
if (proc?.pm2_env?.status !== "online") return false;
|
|
5802
|
+
const pid = Number(proc.pid);
|
|
5803
|
+
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
5804
|
+
if (oldPid != null) {
|
|
5805
|
+
if (pid === oldPid) return false;
|
|
5806
|
+
if (isPidAlive(oldPid)) return false;
|
|
5807
|
+
}
|
|
5808
|
+
return true;
|
|
5809
|
+
}
|
|
5712
5810
|
async function reloadPm2(paths, options = {}) {
|
|
5713
|
-
const { dryRun = false, logger = console } = options;
|
|
5811
|
+
const { dryRun = false, logger = console, appName = null, waitTimeoutMs = 65e3 } = options;
|
|
5714
5812
|
if (dryRun) {
|
|
5715
5813
|
logger.info(`[dryRun] would pm2 startOrReload ${paths.ecosystem} --update-env`);
|
|
5716
5814
|
return;
|
|
5717
5815
|
}
|
|
5816
|
+
let oldPid = null;
|
|
5817
|
+
if (appName) {
|
|
5818
|
+
const before = await getPm2Process(appName, { logger });
|
|
5819
|
+
const n = Number(before?.pid);
|
|
5820
|
+
if (Number.isFinite(n) && n > 0 && before?.pm2_env?.status === "online") {
|
|
5821
|
+
oldPid = n;
|
|
5822
|
+
logger.info(`pm2 ${appName}: reloading (old pid=${oldPid})`);
|
|
5823
|
+
}
|
|
5824
|
+
}
|
|
5718
5825
|
await runShell(`pm2 startOrReload "${paths.ecosystem}" --update-env`, { logger });
|
|
5719
5826
|
logger.info("pm2 reloaded");
|
|
5827
|
+
if (appName) {
|
|
5828
|
+
const proc = await waitPm2(
|
|
5829
|
+
appName,
|
|
5830
|
+
(p) => isFreshOnline(p, oldPid),
|
|
5831
|
+
{
|
|
5832
|
+
timeoutMs: waitTimeoutMs,
|
|
5833
|
+
logger,
|
|
5834
|
+
label: oldPid ? `online on new pid (old ${oldPid} gone)` : "online after reload"
|
|
5835
|
+
}
|
|
5836
|
+
);
|
|
5837
|
+
logger.info(`pm2 ${appName} online pid=${proc?.pid ?? "?"}`);
|
|
5838
|
+
}
|
|
5839
|
+
}
|
|
5840
|
+
async function stopPm2(appName, options = {}) {
|
|
5841
|
+
const { dryRun = false, logger = console, waitTimeoutMs = 65e3 } = options;
|
|
5842
|
+
if (dryRun) {
|
|
5843
|
+
logger.info(`[dryRun] would pm2 stop ${appName}`);
|
|
5844
|
+
return;
|
|
5845
|
+
}
|
|
5846
|
+
const before = await getPm2Process(appName, { logger });
|
|
5847
|
+
if (!before) {
|
|
5848
|
+
logger.info(`pm2 ${appName}: not present (already stopped)`);
|
|
5849
|
+
return;
|
|
5850
|
+
}
|
|
5851
|
+
if (before.pm2_env?.status === "stopped") {
|
|
5852
|
+
logger.info(`pm2 ${appName}: already stopped`);
|
|
5853
|
+
return;
|
|
5854
|
+
}
|
|
5855
|
+
const oldPid = Number(before.pid);
|
|
5856
|
+
await runShell(`pm2 stop "${appName}"`, { logger });
|
|
5857
|
+
await waitPm2(
|
|
5858
|
+
appName,
|
|
5859
|
+
(proc) => {
|
|
5860
|
+
if (proc && proc.pm2_env?.status !== "stopped") return false;
|
|
5861
|
+
if (Number.isFinite(oldPid) && oldPid > 0 && isPidAlive(oldPid)) return false;
|
|
5862
|
+
return true;
|
|
5863
|
+
},
|
|
5864
|
+
{ timeoutMs: waitTimeoutMs, logger, label: "stopped" }
|
|
5865
|
+
);
|
|
5866
|
+
logger.info(`pm2 ${appName} stopped`);
|
|
5867
|
+
}
|
|
5868
|
+
async function startPm2(paths, options = {}) {
|
|
5869
|
+
const { dryRun = false, logger = console, appName = null, waitTimeoutMs = 65e3 } = options;
|
|
5870
|
+
if (dryRun) {
|
|
5871
|
+
logger.info(`[dryRun] would pm2 start ${paths.ecosystem} --update-env`);
|
|
5872
|
+
return;
|
|
5873
|
+
}
|
|
5874
|
+
await runShell(`pm2 start "${paths.ecosystem}" --update-env`, { logger });
|
|
5875
|
+
logger.info("pm2 started");
|
|
5876
|
+
if (appName) {
|
|
5877
|
+
const proc = await waitPm2(
|
|
5878
|
+
appName,
|
|
5879
|
+
(p) => isFreshOnline(p, null),
|
|
5880
|
+
{ timeoutMs: waitTimeoutMs, logger, label: "online after start" }
|
|
5881
|
+
);
|
|
5882
|
+
logger.info(`pm2 ${appName} online pid=${proc?.pid ?? "?"}`);
|
|
5883
|
+
}
|
|
5720
5884
|
}
|
|
5721
5885
|
|
|
5722
5886
|
// src/deploy/nginx.js
|
|
@@ -5945,10 +6109,26 @@ async function requireDeployRoot(parentDir, serviceRoot) {
|
|
|
5945
6109
|
This is meant to run on the target host (where ${parentDir} exists). For a local dry run use --appsRoot=/tmp/<service>.`
|
|
5946
6110
|
);
|
|
5947
6111
|
}
|
|
6112
|
+
function resolveKillTimeoutMs(pm2) {
|
|
6113
|
+
const explicit = Number(pm2?.killTimeout);
|
|
6114
|
+
if (Number.isFinite(explicit) && explicit > 0) return Math.floor(explicit);
|
|
6115
|
+
const stopSec = Number(pm2?.stopAllowance);
|
|
6116
|
+
if (Number.isFinite(stopSec) && stopSec > 0) return Math.floor(stopSec * 1e3) + 5e3;
|
|
6117
|
+
return 65e3;
|
|
6118
|
+
}
|
|
6119
|
+
function resolvePm2Args(pm2) {
|
|
6120
|
+
const base = String(pm2?.args ?? "").trim();
|
|
6121
|
+
const stopSec = Number(pm2?.stopAllowance);
|
|
6122
|
+
if (!Number.isFinite(stopSec) || stopSec <= 0) return base;
|
|
6123
|
+
if (/(?:^|\s)--stopAllowance=/.test(base)) return base;
|
|
6124
|
+
return `${base}${base ? " " : ""}--stopAllowance=${Math.floor(stopSec)}`.trim();
|
|
6125
|
+
}
|
|
5948
6126
|
function buildEcosystemConfig(service, paths) {
|
|
5949
6127
|
const { pm2 } = service;
|
|
5950
6128
|
const outLog = (0, import_node_path8.join)(paths.logs, `${pm2.appName}.out.log`);
|
|
5951
6129
|
const errLog = (0, import_node_path8.join)(paths.logs, `${pm2.appName}.err.log`);
|
|
6130
|
+
const killTimeoutMs = resolveKillTimeoutMs(pm2);
|
|
6131
|
+
const args = resolvePm2Args(pm2);
|
|
5952
6132
|
return `/**
|
|
5953
6133
|
* pm2 ecosystem for ${service.name} \u2014 written by cli-toolkit deploy from the
|
|
5954
6134
|
* service manifest (init/deploy). Do not hand-edit; change pm2.* in the
|
|
@@ -5960,7 +6140,7 @@ module.exports = {
|
|
|
5960
6140
|
name: "${pm2.appName}",
|
|
5961
6141
|
script: "${pm2.script}",
|
|
5962
6142
|
cwd: "${paths.current}",
|
|
5963
|
-
args:
|
|
6143
|
+
args: ${JSON.stringify(args)},
|
|
5964
6144
|
instances: 1,
|
|
5965
6145
|
exec_mode: "fork",
|
|
5966
6146
|
autorestart: true,
|
|
@@ -5968,6 +6148,8 @@ module.exports = {
|
|
|
5968
6148
|
max_restarts: 10,
|
|
5969
6149
|
restart_delay: 2000,
|
|
5970
6150
|
max_memory_restart: "1500M",
|
|
6151
|
+
// Grace window after SIGINT/SIGTERM before SIGKILL (ms). Align with --stopAllowance.
|
|
6152
|
+
kill_timeout: ${killTimeoutMs},
|
|
5971
6153
|
out_file: "${outLog}",
|
|
5972
6154
|
error_file: "${errLog}",
|
|
5973
6155
|
merge_logs: true,
|
|
@@ -6168,15 +6350,27 @@ async function bootstrapHost(service, options = {}) {
|
|
|
6168
6350
|
}
|
|
6169
6351
|
|
|
6170
6352
|
// src/deploy/deploy-service.js
|
|
6353
|
+
var import_promises13 = require("fs/promises");
|
|
6354
|
+
function resolveKillTimeoutMs2(service) {
|
|
6355
|
+
const explicit = Number(service.pm2?.killTimeout);
|
|
6356
|
+
if (Number.isFinite(explicit) && explicit > 0) return Math.floor(explicit);
|
|
6357
|
+
const stopSec = Number(service.pm2?.stopAllowance);
|
|
6358
|
+
if (Number.isFinite(stopSec) && stopSec > 0) return Math.floor(stopSec * 1e3) + 5e3;
|
|
6359
|
+
return 65e3;
|
|
6360
|
+
}
|
|
6171
6361
|
async function deployService(service, options = {}) {
|
|
6172
6362
|
const {
|
|
6173
6363
|
dryRun = false,
|
|
6174
6364
|
skipPull = false,
|
|
6175
6365
|
skipTests = false,
|
|
6176
6366
|
skipNginx = false,
|
|
6367
|
+
stopFirst = false,
|
|
6177
6368
|
logger = console
|
|
6178
6369
|
} = options;
|
|
6179
6370
|
const paths = servicePaths(service);
|
|
6371
|
+
const appName = service.pm2.appName;
|
|
6372
|
+
const killTimeoutMs = resolveKillTimeoutMs2(service);
|
|
6373
|
+
const waitTimeoutMs = killTimeoutMs + 1e4;
|
|
6180
6374
|
await initServiceStructure(service, { dryRun, logger });
|
|
6181
6375
|
if (!skipPull) await pullRepo(service, { dryRun, logger });
|
|
6182
6376
|
await syncEnv(service, { dryRun, logger });
|
|
@@ -6184,21 +6378,38 @@ async function deployService(service, options = {}) {
|
|
|
6184
6378
|
await writeReleaseBuildInfo(service, releasePath, { stamp, dryRun, logger });
|
|
6185
6379
|
await installDeps(service, releasePath, paths, { dryRun, logger });
|
|
6186
6380
|
if (!skipTests) await runReleaseTests(service, releasePath, paths, { dryRun, logger });
|
|
6187
|
-
|
|
6188
|
-
|
|
6189
|
-
|
|
6381
|
+
let previousReleaseName = null;
|
|
6382
|
+
try {
|
|
6383
|
+
const prev = await (0, import_promises13.readlink)(paths.current);
|
|
6384
|
+
previousReleaseName = prev.split("/").pop() || null;
|
|
6385
|
+
} catch {
|
|
6386
|
+
}
|
|
6387
|
+
if (stopFirst) {
|
|
6388
|
+
logger.info(`deploy mode=stopFirst app=${appName} killTimeoutMs=${killTimeoutMs}`);
|
|
6389
|
+
await stopPm2(appName, { dryRun, logger, waitTimeoutMs });
|
|
6390
|
+
await activateRelease(releasePath, paths, { dryRun, logger });
|
|
6391
|
+
await pruneReleases(service, paths, { dryRun, logger });
|
|
6392
|
+
await startPm2(paths, { dryRun, logger, appName, waitTimeoutMs });
|
|
6393
|
+
} else {
|
|
6394
|
+
logger.info(
|
|
6395
|
+
`deploy mode=rolling app=${appName} killTimeoutMs=${killTimeoutMs}` + (previousReleaseName ? ` previous=${previousReleaseName}` : "")
|
|
6396
|
+
);
|
|
6397
|
+
await activateRelease(releasePath, paths, { dryRun, logger });
|
|
6398
|
+
await reloadPm2(paths, { dryRun, logger, appName, waitTimeoutMs });
|
|
6399
|
+
await pruneReleases(service, paths, { dryRun, logger });
|
|
6400
|
+
}
|
|
6190
6401
|
if (!skipNginx) await enableNginxUpstream(service, { dryRun, logger });
|
|
6191
|
-
const summary = `deploy complete stamp=${stamp} dryRun=${dryRun}`;
|
|
6402
|
+
const summary = `deploy complete stamp=${stamp} mode=${stopFirst ? "stopFirst" : "rolling"} dryRun=${dryRun}`;
|
|
6192
6403
|
logger.info(summary);
|
|
6193
6404
|
if (!dryRun) await appendDeployLog(paths.deployLog, summary);
|
|
6194
|
-
return { stamp, releasePath };
|
|
6405
|
+
return { stamp, releasePath, mode: stopFirst ? "stopFirst" : "rolling" };
|
|
6195
6406
|
}
|
|
6196
6407
|
|
|
6197
6408
|
// src/deploy/provision-service.js
|
|
6198
|
-
var
|
|
6409
|
+
var import_promises14 = require("fs/promises");
|
|
6199
6410
|
async function pathExists6(path5) {
|
|
6200
6411
|
try {
|
|
6201
|
-
await (0,
|
|
6412
|
+
await (0, import_promises14.access)(path5);
|
|
6202
6413
|
return true;
|
|
6203
6414
|
} catch {
|
|
6204
6415
|
return false;
|
|
@@ -6232,7 +6443,7 @@ async function provisionService(service, options = {}) {
|
|
|
6232
6443
|
}
|
|
6233
6444
|
|
|
6234
6445
|
// src/deploy/rollback-service.js
|
|
6235
|
-
var
|
|
6446
|
+
var import_promises15 = require("fs/promises");
|
|
6236
6447
|
async function rollbackService(service, options = {}) {
|
|
6237
6448
|
const { release: targetName, dryRun = false, logger = console } = options;
|
|
6238
6449
|
const paths = servicePaths(service);
|
|
@@ -6240,7 +6451,7 @@ async function rollbackService(service, options = {}) {
|
|
|
6240
6451
|
if (releases.length === 0) throw new Error("No releases to roll back to");
|
|
6241
6452
|
let activeName = null;
|
|
6242
6453
|
try {
|
|
6243
|
-
const target = await (0,
|
|
6454
|
+
const target = await (0, import_promises15.readlink)(paths.current);
|
|
6244
6455
|
activeName = target.split("/").pop();
|
|
6245
6456
|
} catch {
|
|
6246
6457
|
throw new Error("No active release (current symlink missing)");
|
|
@@ -6267,14 +6478,14 @@ async function rollbackService(service, options = {}) {
|
|
|
6267
6478
|
}
|
|
6268
6479
|
|
|
6269
6480
|
// src/deploy/ssh-remote.js
|
|
6270
|
-
var
|
|
6481
|
+
var import_promises16 = require("fs/promises");
|
|
6271
6482
|
var import_node_os3 = require("os");
|
|
6272
6483
|
var import_node_path10 = require("path");
|
|
6273
6484
|
var import_node_child_process4 = require("child_process");
|
|
6274
6485
|
var REMOTE_CLI_REL = "node_modules/@nmakarov/cli-toolkit/scripts/deploy/cli.js";
|
|
6275
6486
|
async function pathExists7(path5) {
|
|
6276
6487
|
try {
|
|
6277
|
-
await (0,
|
|
6488
|
+
await (0, import_promises16.access)(path5);
|
|
6278
6489
|
return true;
|
|
6279
6490
|
} catch {
|
|
6280
6491
|
return false;
|
|
@@ -6366,9 +6577,9 @@ async function ensureEnvOnRemote(host, service, options = {}) {
|
|
|
6366
6577
|
if (!await pathExists7(localPath)) return false;
|
|
6367
6578
|
logger.info(`copying .env ${localPath} \u2192 ${host}:${paths.repoEnv}`);
|
|
6368
6579
|
await sshRun(host, `mkdir -p ${shellQuote((0, import_node_path10.dirname)(paths.repoEnv))}`, { logger });
|
|
6369
|
-
const scrubbed = scrubEnvContent(await (0,
|
|
6580
|
+
const scrubbed = scrubEnvContent(await (0, import_promises16.readFile)(localPath, "utf8"), service.envScrubPatterns ?? []);
|
|
6370
6581
|
const tmp = (0, import_node_path10.join)((0, import_node_os3.tmpdir)(), `deploy-env-${Date.now()}`);
|
|
6371
|
-
await (0,
|
|
6582
|
+
await (0, import_promises16.writeFile)(tmp, scrubbed, { mode: 384 });
|
|
6372
6583
|
await scp(tmp, `${host}:${paths.repoEnv}`, { logger });
|
|
6373
6584
|
await sshRun(host, `chmod 600 ${shellQuote(paths.repoEnv)}`, { logger });
|
|
6374
6585
|
return true;
|
|
@@ -7702,7 +7913,7 @@ var TaskShellCommand = class extends AbstractTask {
|
|
|
7702
7913
|
|
|
7703
7914
|
// src/tasks/coreTasks/TaskSystemInfo.js
|
|
7704
7915
|
var import_node_os5 = __toESM(require("os"), 1);
|
|
7705
|
-
var
|
|
7916
|
+
var import_promises17 = __toESM(require("fs/promises"), 1);
|
|
7706
7917
|
function toGb(valueBytes) {
|
|
7707
7918
|
return `${(valueBytes / 1024 ** 3).toFixed(2)} GB`;
|
|
7708
7919
|
}
|
|
@@ -7710,7 +7921,7 @@ function toMb(valueBytes) {
|
|
|
7710
7921
|
return `${(valueBytes / 1024 ** 2).toFixed(2)} MB`;
|
|
7711
7922
|
}
|
|
7712
7923
|
async function getDiskStats() {
|
|
7713
|
-
const stats = await
|
|
7924
|
+
const stats = await import_promises17.default.statfs("/");
|
|
7714
7925
|
const total = Number(stats.bsize) * Number(stats.blocks);
|
|
7715
7926
|
const free = Number(stats.bsize) * Number(stats.bavail);
|
|
7716
7927
|
const used = total - free;
|
|
@@ -7863,7 +8074,7 @@ var TaskStopRunner = class extends AbstractTask {
|
|
|
7863
8074
|
*/
|
|
7864
8075
|
static async resolveCustomParams(context, overrides = {}) {
|
|
7865
8076
|
const merged = AbstractTask._mergeTypedParams(context, "task-stop", {
|
|
7866
|
-
allowanceMs: "number default
|
|
8077
|
+
allowanceMs: "number default 60000"
|
|
7867
8078
|
}, overrides);
|
|
7868
8079
|
const allowanceMs = Number(merged.allowanceMs);
|
|
7869
8080
|
if (!Number.isFinite(allowanceMs) || allowanceMs < 0) {
|
|
@@ -7877,7 +8088,7 @@ var TaskStopRunner = class extends AbstractTask {
|
|
|
7877
8088
|
* @returns {Promise<{ success: true, results: { stopRunner: true, allowanceMs: number, message: string } }>}
|
|
7878
8089
|
*/
|
|
7879
8090
|
async run() {
|
|
7880
|
-
const allowanceMs = Number(this.task?.params?.allowanceMs ??
|
|
8091
|
+
const allowanceMs = Number(this.task?.params?.allowanceMs ?? 6e4);
|
|
7881
8092
|
this.context.logger.warn?.(`[TaskStopRunner] stop requested (allowanceMs=${allowanceMs})`);
|
|
7882
8093
|
return {
|
|
7883
8094
|
success: true,
|
|
@@ -8562,7 +8773,7 @@ function normalizeRegistry(registry) {
|
|
|
8562
8773
|
if (registry instanceof TasksRegistry) return registry;
|
|
8563
8774
|
return new TasksRegistry().addMany(registry);
|
|
8564
8775
|
}
|
|
8565
|
-
async function enqueueStopTask(context, serviceGroup, queueName = "tasks", allowanceMs =
|
|
8776
|
+
async function enqueueStopTask(context, serviceGroup, queueName = "tasks", allowanceMs = 6e4) {
|
|
8566
8777
|
return enqueueTask(context, {
|
|
8567
8778
|
queueName,
|
|
8568
8779
|
name: "stopRunner",
|
|
@@ -8701,7 +8912,7 @@ async function executeClaimedTask(context, tasksTable, historyTable, row, regist
|
|
|
8701
8912
|
await db(tasksTable).where({ id: row.id }).delete();
|
|
8702
8913
|
}
|
|
8703
8914
|
const stopRunnerRequested = !!(results && typeof results === "object" && results.stopRunner === true);
|
|
8704
|
-
const stopAllowanceMs = stopRunnerRequested ? Number(results.allowanceMs ??
|
|
8915
|
+
const stopAllowanceMs = stopRunnerRequested ? Number(results.allowanceMs ?? 6e4) : 0;
|
|
8705
8916
|
return { stopRunnerRequested, stopAllowanceMs };
|
|
8706
8917
|
}
|
|
8707
8918
|
function shuffleTaskRowsInPlace(rows) {
|
|
@@ -8791,7 +9002,7 @@ async function runTasksLoop(context, options) {
|
|
|
8791
9002
|
const runningTaskInstances = /* @__PURE__ */ new Map();
|
|
8792
9003
|
let runningControlPromise = null;
|
|
8793
9004
|
let stopRequested = false;
|
|
8794
|
-
let stopAllowanceMs =
|
|
9005
|
+
let stopAllowanceMs = Number(context.stopAllowanceMs) > 0 ? Number(context.stopAllowanceMs) : 6e4;
|
|
8795
9006
|
context.tasksRunnerStop = false;
|
|
8796
9007
|
let registryReg = null;
|
|
8797
9008
|
let registryInterval = null;
|
|
@@ -8858,7 +9069,7 @@ async function runTasksLoop(context, options) {
|
|
|
8858
9069
|
).then(async (outcome) => {
|
|
8859
9070
|
if (outcome.stopRunnerRequested && !stopRequested) {
|
|
8860
9071
|
stopRequested = true;
|
|
8861
|
-
stopAllowanceMs = outcome.stopAllowanceMs ||
|
|
9072
|
+
stopAllowanceMs = outcome.stopAllowanceMs || stopAllowanceMs;
|
|
8862
9073
|
context.tasksRunnerStop = true;
|
|
8863
9074
|
await signalRunningTasksStop(context, runningTaskInstances, stopAllowanceMs);
|
|
8864
9075
|
}
|
|
@@ -8884,7 +9095,7 @@ async function runTasksLoop(context, options) {
|
|
|
8884
9095
|
const p = executeClaimedTask(context, tasksTable, historyTable, claimed, registry, runningTaskInstances).then(async (outcome) => {
|
|
8885
9096
|
if (outcome.stopRunnerRequested && !stopRequested) {
|
|
8886
9097
|
stopRequested = true;
|
|
8887
|
-
stopAllowanceMs = outcome.stopAllowanceMs ||
|
|
9098
|
+
stopAllowanceMs = outcome.stopAllowanceMs || stopAllowanceMs;
|
|
8888
9099
|
context.tasksRunnerStop = true;
|
|
8889
9100
|
await signalRunningTasksStop(context, runningTaskInstances, stopAllowanceMs);
|
|
8890
9101
|
}
|
|
@@ -8905,7 +9116,9 @@ async function runTasksLoop(context, options) {
|
|
|
8905
9116
|
}
|
|
8906
9117
|
}
|
|
8907
9118
|
if (context.isStop() && !stopRequested) {
|
|
8908
|
-
|
|
9119
|
+
stopRequested = true;
|
|
9120
|
+
stopAllowanceMs = Number(context.stopAllowanceMs) > 0 ? Number(context.stopAllowanceMs) : stopAllowanceMs;
|
|
9121
|
+
await signalRunningTasksStop(context, runningTaskInstances, stopAllowanceMs);
|
|
8909
9122
|
}
|
|
8910
9123
|
if (runningPromises.size > 0) {
|
|
8911
9124
|
if (stopRequested) {
|
|
@@ -9190,11 +9403,14 @@ var TasksManager = class _TasksManager {
|
|
|
9190
9403
|
ensureTasksRuntime,
|
|
9191
9404
|
flushTaskIpcLogs,
|
|
9192
9405
|
getArgsInstance,
|
|
9406
|
+
getPm2Process,
|
|
9193
9407
|
h,
|
|
9194
9408
|
initServiceStructure,
|
|
9195
9409
|
installDeps,
|
|
9196
9410
|
installOperatorShell,
|
|
9197
9411
|
ipcFileLogsTableNameForSourceResource,
|
|
9412
|
+
isFreshOnline,
|
|
9413
|
+
isPidAlive,
|
|
9198
9414
|
joiEdateType,
|
|
9199
9415
|
joiStringArrayType,
|
|
9200
9416
|
listAliveRunnerHeartbeats,
|
|
@@ -9236,6 +9452,7 @@ var TasksManager = class _TasksManager {
|
|
|
9236
9452
|
resolveSteps,
|
|
9237
9453
|
rollbackService,
|
|
9238
9454
|
run,
|
|
9455
|
+
runCapture,
|
|
9239
9456
|
runNodeTaskScript,
|
|
9240
9457
|
runReleaseTests,
|
|
9241
9458
|
runRemoteCli,
|
|
@@ -9253,6 +9470,8 @@ var TasksManager = class _TasksManager {
|
|
|
9253
9470
|
showScreen,
|
|
9254
9471
|
showWordGridScreen,
|
|
9255
9472
|
sshRun,
|
|
9473
|
+
startPm2,
|
|
9474
|
+
stopPm2,
|
|
9256
9475
|
syncEnv,
|
|
9257
9476
|
taskHistoryInsertFromQueueRow,
|
|
9258
9477
|
timeMatcher,
|
|
@@ -9270,6 +9489,7 @@ var TasksManager = class _TasksManager {
|
|
|
9270
9489
|
useRef,
|
|
9271
9490
|
useState,
|
|
9272
9491
|
waitForTaskResult,
|
|
9492
|
+
waitPm2,
|
|
9273
9493
|
writeReleaseBuildInfo
|
|
9274
9494
|
});
|
|
9275
9495
|
//# sourceMappingURL=index.cjs.map
|