← back to AbramsEgo
use owner-safe PM2 CLI wrapper
c19e2fecb3323e953c7ba32dcf1507fa40d1e36c · 2026-08-30 20:54:49 -0700 · Steve
Files touched
Diff
commit c19e2fecb3323e953c7ba32dcf1507fa40d1e36c
Author: Steve <steve@designerwallcoverings.com>
Date: Sun Aug 30 20:54:49 2026 -0700
use owner-safe PM2 CLI wrapper
---
server.js | 27 +++------------------------
1 file changed, 3 insertions(+), 24 deletions(-)
diff --git a/server.js b/server.js
index 2771885b..6547d257 100644
--- a/server.js
+++ b/server.js
@@ -98,29 +98,8 @@ function sh(cmd, args, timeoutMs = 8000) {
});
}
-// TK-10970: serialize local PM2 CLI access with the same lock used by the
-// fleet keepalive and microsite crawler. Concurrent `pm2 jlist` calls can fork
-// a socket-less God daemon during a transient rpc.sock access race.
-const PM2_CLI_LOCK = path.join(process.env.PM2_HOME || path.join(HOME, '.pm2'), 'cli.lock.d');
-async function withPm2CliLock(fn) {
- const deadline = Date.now() + 10000;
- const staleMs = 8000;
- let held = false;
- while (Date.now() < deadline) {
- try { await fs.promises.mkdir(PM2_CLI_LOCK); held = true; break; }
- catch (e) {
- if (e.code !== 'EEXIST') break;
- try {
- const st = await fs.promises.stat(PM2_CLI_LOCK);
- if (Date.now() - st.mtimeMs > staleMs) { await fs.promises.rmdir(PM2_CLI_LOCK); continue; }
- } catch {}
- await new Promise(resolve => setTimeout(resolve, 80));
- }
- }
- if (!held) return { ok: false, out: '', err: 'pm2 CLI lock unavailable' };
- try { return await fn(); }
- finally { try { await fs.promises.rmdir(PM2_CLI_LOCK); } catch {} }
-}
+// TK-10970: all local PM2 CLI calls share the owner-checked shlock wrapper.
+const PM2_SERIALIZED = path.join(HOME, '.claude', 'skills', 'keep-alive', 'proposals', 'TK-10970', 'pm2-serialized.js');
async function fetchJSON(url, timeoutMs = 5000) {
const ctrl = new AbortController();
const t = setTimeout(() => ctrl.abort(), timeoutMs);
@@ -237,7 +216,7 @@ async function collectLocalFleet() {
const inCooldown = Date.now() - jlistFailedAt < JLIST_COOLDOWN_MS;
const r = inCooldown
? { ok: false, out: '', err: 'jlist cooldown after recent failure' }
- : await withPm2CliLock(() => sh(pm2Bin, ['jlist'], 7000));
+ : await sh(process.execPath, [PM2_SERIALIZED, 'jlist'], 22000);
let list = null;
if (r.ok) { try { list = JSON.parse(r.out); } catch (e) { /* fall through to cache */ } }
if (!inCooldown && !list) jlistFailedAt = Date.now();
← 234ef754 auto-data-snapshot: 2026-08-30T20:54:26 (1 data files) — dat
·
back to AbramsEgo
·
auto-data-snapshot: 2026-08-30T21:32:01 (1 data files) — dat fe659e3a →