@nmakarov/cli-toolkit 0.53.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/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,
@@ -5749,6 +5751,16 @@ async function pruneReleases(service, paths, options = {}) {
5749
5751
  function sleep(ms) {
5750
5752
  return new Promise((resolve3) => setTimeout(resolve3, ms));
5751
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
+ }
5752
5764
  async function getPm2Process(appName, options = {}) {
5753
5765
  const { logger } = options;
5754
5766
  const { stdout } = await runCapture("bash", ["-lc", "pm2 jlist"], { logger });
@@ -5785,21 +5797,44 @@ async function waitPm2(appName, predicate, options = {}) {
5785
5797
  `pm2 wait timed out after ${timeoutMs}ms for ${appName} (${label}); last status=${lastStatus}`
5786
5798
  );
5787
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
+ }
5788
5810
  async function reloadPm2(paths, options = {}) {
5789
5811
  const { dryRun = false, logger = console, appName = null, waitTimeoutMs = 65e3 } = options;
5790
5812
  if (dryRun) {
5791
5813
  logger.info(`[dryRun] would pm2 startOrReload ${paths.ecosystem} --update-env`);
5792
5814
  return;
5793
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
+ }
5794
5825
  await runShell(`pm2 startOrReload "${paths.ecosystem}" --update-env`, { logger });
5795
5826
  logger.info("pm2 reloaded");
5796
5827
  if (appName) {
5797
- await waitPm2(
5828
+ const proc = await waitPm2(
5798
5829
  appName,
5799
- (proc) => proc?.pm2_env?.status === "online",
5800
- { timeoutMs: waitTimeoutMs, logger, label: "online after reload" }
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
+ }
5801
5836
  );
5802
- logger.info(`pm2 ${appName} online`);
5837
+ logger.info(`pm2 ${appName} online pid=${proc?.pid ?? "?"}`);
5803
5838
  }
5804
5839
  }
5805
5840
  async function stopPm2(appName, options = {}) {
@@ -5817,10 +5852,15 @@ async function stopPm2(appName, options = {}) {
5817
5852
  logger.info(`pm2 ${appName}: already stopped`);
5818
5853
  return;
5819
5854
  }
5855
+ const oldPid = Number(before.pid);
5820
5856
  await runShell(`pm2 stop "${appName}"`, { logger });
5821
5857
  await waitPm2(
5822
5858
  appName,
5823
- (proc) => !proc || proc.pm2_env?.status === "stopped",
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
+ },
5824
5864
  { timeoutMs: waitTimeoutMs, logger, label: "stopped" }
5825
5865
  );
5826
5866
  logger.info(`pm2 ${appName} stopped`);
@@ -5834,12 +5874,12 @@ async function startPm2(paths, options = {}) {
5834
5874
  await runShell(`pm2 start "${paths.ecosystem}" --update-env`, { logger });
5835
5875
  logger.info("pm2 started");
5836
5876
  if (appName) {
5837
- await waitPm2(
5877
+ const proc = await waitPm2(
5838
5878
  appName,
5839
- (proc) => proc?.pm2_env?.status === "online",
5879
+ (p) => isFreshOnline(p, null),
5840
5880
  { timeoutMs: waitTimeoutMs, logger, label: "online after start" }
5841
5881
  );
5842
- logger.info(`pm2 ${appName} online`);
5882
+ logger.info(`pm2 ${appName} online pid=${proc?.pid ?? "?"}`);
5843
5883
  }
5844
5884
  }
5845
5885
 
@@ -9369,6 +9409,8 @@ var TasksManager = class _TasksManager {
9369
9409
  installDeps,
9370
9410
  installOperatorShell,
9371
9411
  ipcFileLogsTableNameForSourceResource,
9412
+ isFreshOnline,
9413
+ isPidAlive,
9372
9414
  joiEdateType,
9373
9415
  joiStringArrayType,
9374
9416
  listAliveRunnerHeartbeats,