@nmakarov/cli-toolkit 0.53.0 → 0.57.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/args.cjs +4 -0
- package/dist/args.cjs.map +1 -1
- package/dist/args.js +4 -0
- package/dist/args.js.map +1 -1
- package/dist/cli-runner.cjs +6 -0
- package/dist/cli-runner.cjs.map +1 -1
- package/dist/cli-runner.js +6 -0
- package/dist/cli-runner.js.map +1 -1
- package/dist/deploy.cjs +73 -8
- package/dist/deploy.cjs.map +1 -1
- package/dist/deploy.js +71 -8
- package/dist/deploy.js.map +1 -1
- package/dist/index.cjs +77 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +75 -8
- package/dist/index.js.map +1 -1
- package/dist/init.cjs +6 -0
- package/dist/init.cjs.map +1 -1
- package/dist/init.js +6 -0
- package/dist/init.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1153,6 +1153,8 @@ __export(src_exports, {
|
|
|
1153
1153
|
installDeps: () => installDeps,
|
|
1154
1154
|
installOperatorShell: () => installOperatorShell,
|
|
1155
1155
|
ipcFileLogsTableNameForSourceResource: () => ipcFileLogsTableNameForSourceResource,
|
|
1156
|
+
isFreshOnline: () => isFreshOnline,
|
|
1157
|
+
isPidAlive: () => isPidAlive,
|
|
1156
1158
|
joiEdateType: () => joiEdateType,
|
|
1157
1159
|
joiStringArrayType: () => joiStringArrayType,
|
|
1158
1160
|
listAliveRunnerHeartbeats: () => listServicesRegistry,
|
|
@@ -1269,6 +1271,10 @@ var Args = class _Args {
|
|
|
1269
1271
|
this.parseArgs(args);
|
|
1270
1272
|
this.env = this.get("env")?.toLowerCase() || "local";
|
|
1271
1273
|
this.loadDotEnv();
|
|
1274
|
+
const envAfterDotEnv = this.get("env")?.toLowerCase();
|
|
1275
|
+
if (envAfterDotEnv) {
|
|
1276
|
+
this.env = envAfterDotEnv;
|
|
1277
|
+
}
|
|
1272
1278
|
this.loadConfigFiles();
|
|
1273
1279
|
this.checkConflicts();
|
|
1274
1280
|
if (context && typeof context.registerCleanup === "function") {
|
|
@@ -5431,6 +5437,8 @@ function servicePaths(service) {
|
|
|
5431
5437
|
current: (0, import_node_path.join)(root, "current"),
|
|
5432
5438
|
sharedEnv: (0, import_node_path.join)(root, "shared", ".env"),
|
|
5433
5439
|
ecosystem: (0, import_node_path.join)(root, "shared", "ecosystem.config.cjs"),
|
|
5440
|
+
/** Preloaded by pm2 `node_args --require` so ENV survives flaky restarts. */
|
|
5441
|
+
ensureEnv: (0, import_node_path.join)(root, "shared", "ensure-env.cjs"),
|
|
5434
5442
|
deployLog: (0, import_node_path.join)(root, "logs", "deploy.log"),
|
|
5435
5443
|
lockHashFile: (0, import_node_path.join)(root, "shared", ".package-lock.sha256")
|
|
5436
5444
|
};
|
|
@@ -5749,6 +5757,16 @@ async function pruneReleases(service, paths, options = {}) {
|
|
|
5749
5757
|
function sleep(ms) {
|
|
5750
5758
|
return new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
5751
5759
|
}
|
|
5760
|
+
function isPidAlive(pid) {
|
|
5761
|
+
const n = Number(pid);
|
|
5762
|
+
if (!Number.isFinite(n) || n <= 0) return false;
|
|
5763
|
+
try {
|
|
5764
|
+
process.kill(n, 0);
|
|
5765
|
+
return true;
|
|
5766
|
+
} catch {
|
|
5767
|
+
return false;
|
|
5768
|
+
}
|
|
5769
|
+
}
|
|
5752
5770
|
async function getPm2Process(appName, options = {}) {
|
|
5753
5771
|
const { logger } = options;
|
|
5754
5772
|
const { stdout } = await runCapture("bash", ["-lc", "pm2 jlist"], { logger });
|
|
@@ -5785,21 +5803,44 @@ async function waitPm2(appName, predicate, options = {}) {
|
|
|
5785
5803
|
`pm2 wait timed out after ${timeoutMs}ms for ${appName} (${label}); last status=${lastStatus}`
|
|
5786
5804
|
);
|
|
5787
5805
|
}
|
|
5806
|
+
function isFreshOnline(proc, oldPid) {
|
|
5807
|
+
if (proc?.pm2_env?.status !== "online") return false;
|
|
5808
|
+
const pid = Number(proc.pid);
|
|
5809
|
+
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
5810
|
+
if (oldPid != null) {
|
|
5811
|
+
if (pid === oldPid) return false;
|
|
5812
|
+
if (isPidAlive(oldPid)) return false;
|
|
5813
|
+
}
|
|
5814
|
+
return true;
|
|
5815
|
+
}
|
|
5788
5816
|
async function reloadPm2(paths, options = {}) {
|
|
5789
5817
|
const { dryRun = false, logger = console, appName = null, waitTimeoutMs = 65e3 } = options;
|
|
5790
5818
|
if (dryRun) {
|
|
5791
5819
|
logger.info(`[dryRun] would pm2 startOrReload ${paths.ecosystem} --update-env`);
|
|
5792
5820
|
return;
|
|
5793
5821
|
}
|
|
5822
|
+
let oldPid = null;
|
|
5823
|
+
if (appName) {
|
|
5824
|
+
const before = await getPm2Process(appName, { logger });
|
|
5825
|
+
const n = Number(before?.pid);
|
|
5826
|
+
if (Number.isFinite(n) && n > 0 && before?.pm2_env?.status === "online") {
|
|
5827
|
+
oldPid = n;
|
|
5828
|
+
logger.info(`pm2 ${appName}: reloading (old pid=${oldPid})`);
|
|
5829
|
+
}
|
|
5830
|
+
}
|
|
5794
5831
|
await runShell(`pm2 startOrReload "${paths.ecosystem}" --update-env`, { logger });
|
|
5795
5832
|
logger.info("pm2 reloaded");
|
|
5796
5833
|
if (appName) {
|
|
5797
|
-
await waitPm2(
|
|
5834
|
+
const proc = await waitPm2(
|
|
5798
5835
|
appName,
|
|
5799
|
-
(
|
|
5800
|
-
{
|
|
5836
|
+
(p) => isFreshOnline(p, oldPid),
|
|
5837
|
+
{
|
|
5838
|
+
timeoutMs: waitTimeoutMs,
|
|
5839
|
+
logger,
|
|
5840
|
+
label: oldPid ? `online on new pid (old ${oldPid} gone)` : "online after reload"
|
|
5841
|
+
}
|
|
5801
5842
|
);
|
|
5802
|
-
logger.info(`pm2 ${appName} online`);
|
|
5843
|
+
logger.info(`pm2 ${appName} online pid=${proc?.pid ?? "?"}`);
|
|
5803
5844
|
}
|
|
5804
5845
|
}
|
|
5805
5846
|
async function stopPm2(appName, options = {}) {
|
|
@@ -5817,10 +5858,15 @@ async function stopPm2(appName, options = {}) {
|
|
|
5817
5858
|
logger.info(`pm2 ${appName}: already stopped`);
|
|
5818
5859
|
return;
|
|
5819
5860
|
}
|
|
5861
|
+
const oldPid = Number(before.pid);
|
|
5820
5862
|
await runShell(`pm2 stop "${appName}"`, { logger });
|
|
5821
5863
|
await waitPm2(
|
|
5822
5864
|
appName,
|
|
5823
|
-
(proc) =>
|
|
5865
|
+
(proc) => {
|
|
5866
|
+
if (proc && proc.pm2_env?.status !== "stopped") return false;
|
|
5867
|
+
if (Number.isFinite(oldPid) && oldPid > 0 && isPidAlive(oldPid)) return false;
|
|
5868
|
+
return true;
|
|
5869
|
+
},
|
|
5824
5870
|
{ timeoutMs: waitTimeoutMs, logger, label: "stopped" }
|
|
5825
5871
|
);
|
|
5826
5872
|
logger.info(`pm2 ${appName} stopped`);
|
|
@@ -5834,12 +5880,12 @@ async function startPm2(paths, options = {}) {
|
|
|
5834
5880
|
await runShell(`pm2 start "${paths.ecosystem}" --update-env`, { logger });
|
|
5835
5881
|
logger.info("pm2 started");
|
|
5836
5882
|
if (appName) {
|
|
5837
|
-
await waitPm2(
|
|
5883
|
+
const proc = await waitPm2(
|
|
5838
5884
|
appName,
|
|
5839
|
-
(
|
|
5885
|
+
(p) => isFreshOnline(p, null),
|
|
5840
5886
|
{ timeoutMs: waitTimeoutMs, logger, label: "online after start" }
|
|
5841
5887
|
);
|
|
5842
|
-
logger.info(`pm2 ${appName} online`);
|
|
5888
|
+
logger.info(`pm2 ${appName} online pid=${proc?.pid ?? "?"}`);
|
|
5843
5889
|
}
|
|
5844
5890
|
}
|
|
5845
5891
|
|
|
@@ -6083,12 +6129,23 @@ function resolvePm2Args(pm2) {
|
|
|
6083
6129
|
if (/(?:^|\s)--stopAllowance=/.test(base)) return base;
|
|
6084
6130
|
return `${base}${base ? " " : ""}--stopAllowance=${Math.floor(stopSec)}`.trim();
|
|
6085
6131
|
}
|
|
6132
|
+
function buildEnsureEnvScript() {
|
|
6133
|
+
return `/**
|
|
6134
|
+
* Written by cli-toolkit deploy (init-structure). Do not hand-edit.
|
|
6135
|
+
* Preloaded via pm2 node_args --require so Args sees ENV=production even when
|
|
6136
|
+
* a post-SIGKILL restart briefly omits ecosystem env (otherwise Db \u2192 local:6032).
|
|
6137
|
+
*/
|
|
6138
|
+
if (!process.env.ENV) process.env.ENV = "production";
|
|
6139
|
+
if (!process.env.NODE_ENV) process.env.NODE_ENV = "production";
|
|
6140
|
+
`;
|
|
6141
|
+
}
|
|
6086
6142
|
function buildEcosystemConfig(service, paths) {
|
|
6087
6143
|
const { pm2 } = service;
|
|
6088
6144
|
const outLog = (0, import_node_path8.join)(paths.logs, `${pm2.appName}.out.log`);
|
|
6089
6145
|
const errLog = (0, import_node_path8.join)(paths.logs, `${pm2.appName}.err.log`);
|
|
6090
6146
|
const killTimeoutMs = resolveKillTimeoutMs(pm2);
|
|
6091
6147
|
const args = resolvePm2Args(pm2);
|
|
6148
|
+
const ensureEnv = paths.ensureEnv;
|
|
6092
6149
|
return `/**
|
|
6093
6150
|
* pm2 ecosystem for ${service.name} \u2014 written by cli-toolkit deploy from the
|
|
6094
6151
|
* service manifest (init/deploy). Do not hand-edit; change pm2.* in the
|
|
@@ -6101,6 +6158,8 @@ module.exports = {
|
|
|
6101
6158
|
script: "${pm2.script}",
|
|
6102
6159
|
cwd: "${paths.current}",
|
|
6103
6160
|
args: ${JSON.stringify(args)},
|
|
6161
|
+
// Absolute --require so ENV is set before Args constructs (see shared/ensure-env.cjs).
|
|
6162
|
+
node_args: ${JSON.stringify(`--require ${ensureEnv}`)},
|
|
6104
6163
|
instances: 1,
|
|
6105
6164
|
exec_mode: "fork",
|
|
6106
6165
|
autorestart: true,
|
|
@@ -6142,9 +6201,17 @@ async function initServiceStructure(service, options = {}) {
|
|
|
6142
6201
|
created.push(dir);
|
|
6143
6202
|
}
|
|
6144
6203
|
const ecosystemExisted = await pathExists4(paths.ecosystem);
|
|
6204
|
+
const ensureEnvExisted = await pathExists4(paths.ensureEnv);
|
|
6145
6205
|
if (!dryRun) {
|
|
6206
|
+
await (0, import_promises11.writeFile)(paths.ensureEnv, buildEnsureEnvScript(), { mode: 420 });
|
|
6146
6207
|
await (0, import_promises11.writeFile)(paths.ecosystem, buildEcosystemConfig(service, paths), { mode: 420 });
|
|
6147
6208
|
}
|
|
6209
|
+
if (ensureEnvExisted) {
|
|
6210
|
+
logger.info(`synced ${paths.ensureEnv}`);
|
|
6211
|
+
} else {
|
|
6212
|
+
created.push(paths.ensureEnv);
|
|
6213
|
+
logger.info(`seeded ${paths.ensureEnv}`);
|
|
6214
|
+
}
|
|
6148
6215
|
if (ecosystemExisted) {
|
|
6149
6216
|
logger.info(`synced ${paths.ecosystem} from manifest`);
|
|
6150
6217
|
} else {
|
|
@@ -9369,6 +9436,8 @@ var TasksManager = class _TasksManager {
|
|
|
9369
9436
|
installDeps,
|
|
9370
9437
|
installOperatorShell,
|
|
9371
9438
|
ipcFileLogsTableNameForSourceResource,
|
|
9439
|
+
isFreshOnline,
|
|
9440
|
+
isPidAlive,
|
|
9372
9441
|
joiEdateType,
|
|
9373
9442
|
joiStringArrayType,
|
|
9374
9443
|
listAliveRunnerHeartbeats,
|