feat(pm2): update PM2 configuration and introduce new start script
Deploy to Raspberry Pi / deploy (push) Canceled after 37s

- Updated PM2 version to 6.0.14 in package.json and pnpm-lock.yaml for improved stability.
- Changed interpreter for PM2 processes to use `process.execPath` for consistency.
- Added a new `start:pm2` script in package.json to streamline PM2 process management.
- Updated README to reflect changes in PM2 usage and instructions for starting the application.
This commit is contained in:
2026-08-23 07:25:25 +07:00
parent c8697532f9
commit 69312c9080
6 changed files with 61 additions and 5 deletions
+4 -1
View File
@@ -168,8 +168,11 @@ pnpm install
pnpm build pnpm build
# Redis must be reachable at REDIS_URL (set REDIS_PASS if Redis requires AUTH) # Redis must be reachable at REDIS_URL (set REDIS_PASS if Redis requires AUTH)
# Put secrets in .env (JFLOW_JWT_SECRET, JFLOW_SECRETS_KEY, REDIS_URL, …) # Put secrets in .env (JFLOW_JWT_SECRET, JFLOW_SECRETS_KEY, REDIS_URL, …)
pm2 start ecosystem.config.cjs # Use in-tree PM2 6.x (same module control.js requires). A global `pm2` 7.x
# against a 6.x daemon pegs CPU even when ls shows only 2 fork instances.
pnpm start:pm2
# UI: http://localhost:8500 # UI: http://localhost:8500
# If you already mixed versions: pnpm pm2 -- kill && pnpm start:pm2
``` ```
Or without the ecosystem file: Or without the ecosystem file:
+5 -2
View File
@@ -3,6 +3,9 @@
* Starts always-on processes only; HTTP (:8700) and workers are owned by * Starts always-on processes only; HTTP (:8700) and workers are owned by
* control.js via PM2 (same as `pnpm dev:pm2`). * control.js via PM2 (same as `pnpm dev:pm2`).
* *
* Use `pnpm start:pm2` (in-tree PM2 6.x). Do not use a global `pm2` 7.x —
* a CLI/daemon version mismatch pegs CPU even with instances: 1.
*
* Prerequisites: `pnpm build` (packages/web/dist), Redis, .env secrets. * Prerequisites: `pnpm build` (packages/web/dist), Redis, .env secrets.
*/ */
const fs = require("fs"); const fs = require("fs");
@@ -41,7 +44,7 @@ module.exports = {
name: "jflow-control", name: "jflow-control",
cwd: root, cwd: root,
script: "packages/server/control.js", script: "packages/server/control.js",
interpreter: "node", interpreter: process.execPath,
instances: 1, instances: 1,
exec_mode: "fork", exec_mode: "fork",
autorestart: true, autorestart: true,
@@ -55,7 +58,7 @@ module.exports = {
name: "jflow-web", name: "jflow-web",
cwd: root, cwd: root,
script: "packages/server/web-server.js", script: "packages/server/web-server.js",
interpreter: "node", interpreter: process.execPath,
instances: 1, instances: 1,
exec_mode: "fork", exec_mode: "fork",
autorestart: true, autorestart: true,
+2
View File
@@ -15,6 +15,8 @@
"start:worker": "pnpm --filter @jerapah-flow/server start:worker", "start:worker": "pnpm --filter @jerapah-flow/server start:worker",
"start:control": "pnpm --filter @jerapah-flow/server start:control", "start:control": "pnpm --filter @jerapah-flow/server start:control",
"start:web": "pnpm --filter @jerapah-flow/server start:web", "start:web": "pnpm --filter @jerapah-flow/server start:web",
"pm2": "node scripts/pm2.mjs",
"start:pm2": "node scripts/pm2.mjs start ecosystem.config.cjs",
"migrate": "pnpm --filter @jerapah-flow/server migrate", "migrate": "pnpm --filter @jerapah-flow/server migrate",
"test": "pnpm --filter @jerapah-flow/shared test && pnpm --filter @jerapah-flow/web test", "test": "pnpm --filter @jerapah-flow/shared test && pnpm --filter @jerapah-flow/web test",
"lint": "pnpm --filter @jerapah-flow/web lint" "lint": "pnpm --filter @jerapah-flow/web lint"
+1 -1
View File
@@ -42,7 +42,7 @@
"nodemailer": "^9.0.5", "nodemailer": "^9.0.5",
"pino": "^10.3.1", "pino": "^10.3.1",
"pino-roll": "^4.0.0", "pino-roll": "^4.0.0",
"pm2": "^6.0.13", "pm2": "6.0.14",
"rss-parser": "^3.13.0", "rss-parser": "^3.13.0",
"ssh2-sftp-client": "^12.1.1", "ssh2-sftp-client": "^12.1.1",
"webdav": "^5.10.0", "webdav": "^5.10.0",
+1 -1
View File
@@ -77,7 +77,7 @@ importers:
specifier: ^4.0.0 specifier: ^4.0.0
version: 4.0.0 version: 4.0.0
pm2: pm2:
specifier: ^6.0.13 specifier: 6.0.14
version: 6.0.14(supports-color@7.2.0) version: 6.0.14(supports-color@7.2.0)
rss-parser: rss-parser:
specifier: ^3.13.0 specifier: ^3.13.0
+48
View File
@@ -0,0 +1,48 @@
#!/usr/bin/env node
/**
* Run the same PM2 binary control.js `require("pm2")` uses.
* A global `pm2` 7.x talking to an in-memory 6.x daemon pegs CPU on start.
*/
import { spawn, spawnSync } from "node:child_process";
import { createRequire } from "node:module";
import path from "node:path";
import { fileURLToPath } from "node:url";
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
const require = createRequire(
path.join(root, "packages/server/package.json"),
);
const pm2Root = path.dirname(require.resolve("pm2/package.json"));
const pm2Bin = path.join(pm2Root, "bin/pm2");
const args = process.argv.slice(2);
function run(pm2Args, opts = {}) {
return spawnSync(process.execPath, [pm2Bin, ...pm2Args], {
cwd: root,
encoding: "utf8",
...opts,
});
}
const cmd = args[0];
if (cmd === "start" || cmd === "restart" || cmd === "reload") {
const probe = run(["ls"], { stdio: ["ignore", "pipe", "pipe"] });
const text = `${probe.stdout ?? ""}${probe.stderr ?? ""}`;
const mem = text.match(/In memory PM2 version:\s*(\S+)/);
const loc = text.match(/Local PM2 version:\s*(\S+)/);
if (mem && loc && mem[1] !== loc[1]) {
console.error(
`[jflow] PM2 daemon ${mem[1]} != CLI ${loc[1]}. Killing the daemon so control.js and the CLI share one version.`,
);
run(["kill"], { stdio: "inherit" });
}
}
const child = spawn(process.execPath, [pm2Bin, ...args], {
cwd: root,
stdio: "inherit",
});
child.on("exit", (code, signal) => {
if (signal) process.kill(process.pid, signal);
process.exit(code ?? 1);
});