@lensmcp/cluster 1.16.30 → 1.16.33
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/executors/gateway/runtime/lens-children.d.ts.map +1 -1
- package/executors/gateway/runtime/lens-children.js +7 -4
- package/executors/gateway/runtime/lifecycle.d.ts +28 -2
- package/executors/gateway/runtime/lifecycle.d.ts.map +1 -1
- package/executors/gateway/runtime/lifecycle.js +150 -13
- package/executors/gateway/runtime/observability.d.ts.map +1 -1
- package/executors/gateway/runtime/observability.js +25 -3
- package/executors/gateway/runtime/server.d.ts.map +1 -1
- package/executors/gateway/runtime/server.js +5 -0
- package/executors/gateway/runtime/types.d.ts +10 -0
- package/executors/gateway/runtime/types.d.ts.map +1 -1
- package/executors/gateway/runtime/workspace-registry.d.ts +20 -2
- package/executors/gateway/runtime/workspace-registry.d.ts.map +1 -1
- package/executors/gateway/runtime/workspace-registry.js +32 -3
- package/main.devserver.js +23 -0
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lens-children.d.ts","sourceRoot":"","sources":["../../../../../../libs/cluster/src/executors/gateway/runtime/lens-children.ts"],"names":[],"mappings":"AASA,OAAO,EAIL,KAAK,UAAU,EAChB,MAAM,kCAAkC,CAAC;AAI1C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAE1D,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAuB,MAAM,SAAS,CAAC;AAQ1F,OAAO,EAA0B,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAM7E;;;;8CAI8C;AAC9C,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO5D;AAED,MAAM,WAAW,YAAY;IAC3B,iBAAiB,EAAE,UAAU,CAAC;IAC9B;;gFAE4E;IAC5E,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC;;6GAEyG;IACzG,sBAAsB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,OAAO,CAAC,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC,CAAC;IACvF;;yGAEqG;IACrG,iBAAiB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,CAAC;IACpE;gHAC4G;IAC5G,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED,wBAAgB,kBAAkB,CAChC,EAAE,EAAE,cAAc,EAClB,GAAG,EAAE,aAAa,EAClB,OAAO,EAAE,qBAAqB,EAE9B,IAAI,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;CAAE,GACzD,YAAY,
|
|
1
|
+
{"version":3,"file":"lens-children.d.ts","sourceRoot":"","sources":["../../../../../../libs/cluster/src/executors/gateway/runtime/lens-children.ts"],"names":[],"mappings":"AASA,OAAO,EAIL,KAAK,UAAU,EAChB,MAAM,kCAAkC,CAAC;AAI1C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAE1D,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAuB,MAAM,SAAS,CAAC;AAQ1F,OAAO,EAA0B,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAM7E;;;;8CAI8C;AAC9C,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO5D;AAED,MAAM,WAAW,YAAY;IAC3B,iBAAiB,EAAE,UAAU,CAAC;IAC9B;;gFAE4E;IAC5E,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC;;6GAEyG;IACzG,sBAAsB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,OAAO,CAAC,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC,CAAC;IACvF;;yGAEqG;IACrG,iBAAiB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,CAAC;IACpE;gHAC4G;IAC5G,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED,wBAAgB,kBAAkB,CAChC,EAAE,EAAE,cAAc,EAClB,GAAG,EAAE,aAAa,EAClB,OAAO,EAAE,qBAAqB,EAE9B,IAAI,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;CAAE,GACzD,YAAY,CAsWd"}
|
|
@@ -137,11 +137,14 @@ deps) {
|
|
|
137
137
|
lensSweeper = setInterval(() => {
|
|
138
138
|
if (rt.stopped())
|
|
139
139
|
return;
|
|
140
|
-
const
|
|
141
|
-
if (
|
|
140
|
+
const wideChangedAt = rt.sourceSetChangedAt ?? 0;
|
|
141
|
+
if (wideChangedAt <= 0 || viteChildren.size === 0)
|
|
142
142
|
return;
|
|
143
143
|
const now = Date.now();
|
|
144
144
|
for (const [child, meta] of viteChildren) {
|
|
145
|
+
// Prefer this app's SCOPED clock — the file set within the subtrees ITS vite can resolve. On the wide
|
|
146
|
+
// clock a backend-only `.ts` add anywhere in the monorepo restarted every frontend (`sourceScopeDirs`).
|
|
147
|
+
const changedAt = rt.sourceSetChangedFor?.get(meta.project) ?? wideChangedAt;
|
|
145
148
|
const last = viteRecycleAt.get(meta.project) ?? 0;
|
|
146
149
|
if (!(0, lifecycle_1.lensFrontendStale)(meta.spawnedAt, last, changedAt, now, cfg))
|
|
147
150
|
continue;
|
|
@@ -186,7 +189,7 @@ deps) {
|
|
|
186
189
|
rt.rebuildRoutes();
|
|
187
190
|
// Publish this workspace to the GLOBAL registry so the root chooser at `${lensHost}/` lists it
|
|
188
191
|
// (and marks it live while this gateway runs). Best-effort — a registry write never blocks serving.
|
|
189
|
-
(0, workspace_registry_1.registerWorkspace)({ key: scope.key, root: rt.root, base: lensBase, pid: process.pid, updatedAt: new Date().toISOString() });
|
|
192
|
+
(0, workspace_registry_1.registerWorkspace)({ key: scope.key, root: rt.root, base: lensBase, pid: process.pid, procStamp: (0, workspace_registry_1.processStamp)(process.pid), updatedAt: new Date().toISOString() });
|
|
190
193
|
console.log(`[gateway] starting lens dashboard → http://localhost:${dashboardPort} (routed at https://${lensHost}${lensBase}/)`);
|
|
191
194
|
emit('info', `lens dashboard up: ${lensHost}${lensBase} → :${dashboardPort}`, 'cluster-lens-dashboard', { kind: 'lens-dashboard-up', host: lensHost, port: dashboardPort, base: lensBase });
|
|
192
195
|
spawnManagedChild('lens-dashboard', process.execPath, [dashboardBundle], {
|
|
@@ -271,7 +274,7 @@ deps) {
|
|
|
271
274
|
rt.registry.appendRoutes(fragment.wsKey, [{ host: lensHost, prefix: lensBase, project: observability_1.LENS_DASHBOARD_PROJECT, target: `http://localhost:${port}` }]);
|
|
272
275
|
// Publish the hosted workspace to the GLOBAL chooser registry (keyed on the DAEMON's pid — the daemon is
|
|
273
276
|
// what keeps it live), so `lensmcp.local/` lists it. Reaped on unregister below.
|
|
274
|
-
(0, workspace_registry_1.registerWorkspace)({ key: fragment.wsKey, root: fragment.root, base: lensBase, pid: process.pid, updatedAt: new Date().toISOString() });
|
|
277
|
+
(0, workspace_registry_1.registerWorkspace)({ key: fragment.wsKey, root: fragment.root, base: lensBase, pid: process.pid, procStamp: (0, workspace_registry_1.processStamp)(process.pid), updatedAt: new Date().toISOString() });
|
|
275
278
|
console.log(`[gateway] hosting dashboard for workspace '${fragment.wsKey}' → http://localhost:${port} (routed at https://${lensHost}${lensBase}/)`);
|
|
276
279
|
emit('info', `lens dashboard up: ${lensHost}${lensBase} → :${port}`, 'cluster-lens-dashboard', { kind: 'lens-dashboard-up', host: lensHost, port, base: lensBase });
|
|
277
280
|
spawnManagedChild(label, process.execPath, [bundle], {
|
|
@@ -3,8 +3,34 @@ import type { Observability } from './observability';
|
|
|
3
3
|
/** Bounded, async, non-blocking walk of the workspace source tree → a signature of the file SET
|
|
4
4
|
* (`<count>:<xor-of-path-hashes>`). Skips node_modules/dist/build/dotdirs + `*-devserver` sock dirs + every
|
|
5
5
|
* GITIGNORED path (runtime output is not source — see `SRC_EXCLUDE`), and only counts source-extension
|
|
6
|
-
* files. Order-independent (readdir order irrelevant) and null-safe.
|
|
7
|
-
|
|
6
|
+
* files. Order-independent (readdir order irrelevant) and null-safe.
|
|
7
|
+
*
|
|
8
|
+
* `scopeDirs` (absolute, from {@link sourceScopeDirs}) narrows the walk to the subtrees a given child could
|
|
9
|
+
* actually resolve, instead of the whole monorepo — see that function for WHY. Omitted ⇒ the whole root
|
|
10
|
+
* (the original workspace-wide behavior, still used when a child's project root is unknown). Root-level
|
|
11
|
+
* loose files are always counted, so a `package.json`/`tsconfig.base.json` add reaches every scope. */
|
|
12
|
+
export declare function sourceSetSignature(root: string, scopeDirs?: readonly string[]): Promise<string>;
|
|
13
|
+
/**
|
|
14
|
+
* PURE: which subtrees a child of `projectRoot` must watch for a "file set changed" verdict.
|
|
15
|
+
*
|
|
16
|
+
* The staleness signal exists to catch a vite/pod whose fs-watcher MISSED a file add. But the signature was
|
|
17
|
+
* workspace-WIDE while its consumers are PER-CHILD, so adding a backend-only `server/apps/auth/**\/*.ts`
|
|
18
|
+
* — a file in no vite module graph — recycled every frontend vite too. Worked failure (foodguard,
|
|
19
|
+
* 2026-07-28): one session writing `server/apps/auth/src/modules/totp/**` added a `.ts` every ~15-20s and
|
|
20
|
+
* held `app.foodguard.local` in near-continuous 502s, 951 recycles in a session, none of them relevant to
|
|
21
|
+
* the dashboard.
|
|
22
|
+
*
|
|
23
|
+
* The scope is the child's OWN top-level bucket plus every bucket that hosts no OTHER gateway-managed
|
|
24
|
+
* project (`managedBuckets`). In a scope-first monorepo (`web/ server/ shared/ ai/ tools/`) that yields
|
|
25
|
+
* `web + shared + ai + tools` for a frontend and `server + shared + ai + tools` for a service: a
|
|
26
|
+
* `server/**` add no longer touches a frontend, while a `shared/contracts` add still reaches both — which
|
|
27
|
+
* is correct, since both import it. It deliberately OVER-includes (a frontend watches `ai/` it may never
|
|
28
|
+
* import) because a false recycle costs a cold start whereas a MISSED one costs a wedged dev server.
|
|
29
|
+
*
|
|
30
|
+
* Both args are absolute; the result is absolute and deduped. An empty result (the project root IS the
|
|
31
|
+
* workspace root, or it sits outside it) means "no narrowing" → the caller falls back to the whole root.
|
|
32
|
+
*/
|
|
33
|
+
export declare function sourceScopeDirs(workspaceRoot: string, projectRoot: string, managedBuckets: readonly string[], topLevelDirs: readonly string[]): string[];
|
|
8
34
|
export interface PodRecycleConfig {
|
|
9
35
|
maxAgeMs: number;
|
|
10
36
|
graceMs: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../../../../../../libs/cluster/src/executors/gateway/runtime/lifecycle.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAapE,OAAO,KAAK,EAAE,aAAa,EAAY,MAAM,iBAAiB,CAAC;AAyE/D
|
|
1
|
+
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../../../../../../libs/cluster/src/executors/gateway/runtime/lifecycle.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAapE,OAAO,KAAK,EAAE,aAAa,EAAY,MAAM,iBAAiB,CAAC;AAyE/D;;;;;;;;wGAQwG;AACxG,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAqCrG;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,eAAe,CAC7B,aAAa,EAAE,MAAM,EACrB,WAAW,EAAE,MAAM,EACnB,cAAc,EAAE,SAAS,MAAM,EAAE,EACjC,YAAY,EAAE,SAAS,MAAM,EAAE,GAC9B,MAAM,EAAE,CAcV;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,UAAU,GAAG,UAAU,GAAG,oBAAoB,CAAC,EACpG,GAAG,EAAE,MAAM,EACX,kBAAkB,EAAE,MAAM,EAC1B,GAAG,EAAE,gBAAgB,GACpB,kBAAkB,GAAG,SAAS,GAAG,IAAI,CAQvC;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,EACrB,kBAAkB,EAAE,MAAM,EAC1B,GAAG,EAAE,MAAM,EACX,GAAG,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAC7D,OAAO,CAMT;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAC;IAChC,YAAY,CAAC,GAAG,EAAE,UAAU,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5C,OAAO,CAAC,GAAG,EAAE,UAAU,GAAG,IAAI,CAAC;IAC/B,WAAW,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAChD,2EAA2E;IAC3E,YAAY,IAAI,MAAM,CAAC,OAAO,CAAC;CAChC;AAED,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,cAAc,EAAE,GAAG,EAAE,aAAa,GAAG,YAAY,CAgcvF"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.sourceSetSignature = sourceSetSignature;
|
|
4
|
+
exports.sourceScopeDirs = sourceScopeDirs;
|
|
4
5
|
exports.podRecycleReason = podRecycleReason;
|
|
5
6
|
exports.lensFrontendStale = lensFrontendStale;
|
|
6
7
|
exports.createServiceLayer = createServiceLayer;
|
|
@@ -90,14 +91,19 @@ async function gitIgnoredPaths(root) {
|
|
|
90
91
|
/** Bounded, async, non-blocking walk of the workspace source tree → a signature of the file SET
|
|
91
92
|
* (`<count>:<xor-of-path-hashes>`). Skips node_modules/dist/build/dotdirs + `*-devserver` sock dirs + every
|
|
92
93
|
* GITIGNORED path (runtime output is not source — see `SRC_EXCLUDE`), and only counts source-extension
|
|
93
|
-
* files. Order-independent (readdir order irrelevant) and null-safe.
|
|
94
|
-
|
|
94
|
+
* files. Order-independent (readdir order irrelevant) and null-safe.
|
|
95
|
+
*
|
|
96
|
+
* `scopeDirs` (absolute, from {@link sourceScopeDirs}) narrows the walk to the subtrees a given child could
|
|
97
|
+
* actually resolve, instead of the whole monorepo — see that function for WHY. Omitted ⇒ the whole root
|
|
98
|
+
* (the original workspace-wide behavior, still used when a child's project root is unknown). Root-level
|
|
99
|
+
* loose files are always counted, so a `package.json`/`tsconfig.base.json` add reaches every scope. */
|
|
100
|
+
async function sourceSetSignature(root, scopeDirs) {
|
|
95
101
|
let count = 0;
|
|
96
102
|
let xor = 0;
|
|
97
103
|
const ignored = await gitIgnoredPaths(root);
|
|
98
104
|
// git speaks posix-relative; `path.relative` yields `\` on win32 — normalize before every lookup.
|
|
99
105
|
const rel = (abs) => path.relative(root, abs).split(path.sep).join('/');
|
|
100
|
-
const walk = async (dir) => {
|
|
106
|
+
const walk = async (dir, recurse = true) => {
|
|
101
107
|
if (count > SCAN_FILE_CAP)
|
|
102
108
|
return;
|
|
103
109
|
let entries;
|
|
@@ -113,6 +119,8 @@ async function sourceSetSignature(root) {
|
|
|
113
119
|
const name = e.name;
|
|
114
120
|
const abs = path.join(dir, name);
|
|
115
121
|
if (e.isDirectory()) {
|
|
122
|
+
if (!recurse)
|
|
123
|
+
continue; // scoped mode: root's own dirs are entered only via scopeDirs
|
|
116
124
|
if (name.startsWith('.') || SRC_EXCLUDE.has(name) || name.endsWith('-devserver'))
|
|
117
125
|
continue;
|
|
118
126
|
if (ignored.has(`${rel(abs)}/`))
|
|
@@ -130,9 +138,56 @@ async function sourceSetSignature(root) {
|
|
|
130
138
|
}
|
|
131
139
|
}
|
|
132
140
|
};
|
|
133
|
-
|
|
141
|
+
if (scopeDirs && scopeDirs.length > 0) {
|
|
142
|
+
await walk(root, false); // root-level loose files only — its subdirs come from scopeDirs
|
|
143
|
+
// Sequential, not Promise.all: `count`/`xor` are shared accumulators, and the xor is
|
|
144
|
+
// order-independent anyway — so concurrency would buy nothing but interleaving risk.
|
|
145
|
+
for (const dir of scopeDirs)
|
|
146
|
+
await walk(dir);
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
await walk(root);
|
|
150
|
+
}
|
|
134
151
|
return `${count}:${(xor >>> 0).toString(36)}`;
|
|
135
152
|
}
|
|
153
|
+
/**
|
|
154
|
+
* PURE: which subtrees a child of `projectRoot` must watch for a "file set changed" verdict.
|
|
155
|
+
*
|
|
156
|
+
* The staleness signal exists to catch a vite/pod whose fs-watcher MISSED a file add. But the signature was
|
|
157
|
+
* workspace-WIDE while its consumers are PER-CHILD, so adding a backend-only `server/apps/auth/**\/*.ts`
|
|
158
|
+
* — a file in no vite module graph — recycled every frontend vite too. Worked failure (foodguard,
|
|
159
|
+
* 2026-07-28): one session writing `server/apps/auth/src/modules/totp/**` added a `.ts` every ~15-20s and
|
|
160
|
+
* held `app.foodguard.local` in near-continuous 502s, 951 recycles in a session, none of them relevant to
|
|
161
|
+
* the dashboard.
|
|
162
|
+
*
|
|
163
|
+
* The scope is the child's OWN top-level bucket plus every bucket that hosts no OTHER gateway-managed
|
|
164
|
+
* project (`managedBuckets`). In a scope-first monorepo (`web/ server/ shared/ ai/ tools/`) that yields
|
|
165
|
+
* `web + shared + ai + tools` for a frontend and `server + shared + ai + tools` for a service: a
|
|
166
|
+
* `server/**` add no longer touches a frontend, while a `shared/contracts` add still reaches both — which
|
|
167
|
+
* is correct, since both import it. It deliberately OVER-includes (a frontend watches `ai/` it may never
|
|
168
|
+
* import) because a false recycle costs a cold start whereas a MISSED one costs a wedged dev server.
|
|
169
|
+
*
|
|
170
|
+
* Both args are absolute; the result is absolute and deduped. An empty result (the project root IS the
|
|
171
|
+
* workspace root, or it sits outside it) means "no narrowing" → the caller falls back to the whole root.
|
|
172
|
+
*/
|
|
173
|
+
function sourceScopeDirs(workspaceRoot, projectRoot, managedBuckets, topLevelDirs) {
|
|
174
|
+
const bucketOf = (abs) => {
|
|
175
|
+
const r = path.relative(workspaceRoot, abs).split(path.sep).filter(Boolean);
|
|
176
|
+
return r.length === 0 || r[0].startsWith('..') ? '' : r[0];
|
|
177
|
+
};
|
|
178
|
+
const own = bucketOf(projectRoot);
|
|
179
|
+
if (!own)
|
|
180
|
+
return []; // project root === workspace root (or outside it) → cannot narrow
|
|
181
|
+
const managed = new Set(managedBuckets.filter(Boolean));
|
|
182
|
+
const keep = new Set([own]);
|
|
183
|
+
for (const d of topLevelDirs) {
|
|
184
|
+
if (d.startsWith('.') || SRC_EXCLUDE.has(d) || d.endsWith('-devserver'))
|
|
185
|
+
continue;
|
|
186
|
+
if (!managed.has(d))
|
|
187
|
+
keep.add(d); // a bucket owned by no managed project = shared/leaf → always watch
|
|
188
|
+
}
|
|
189
|
+
return [...keep].sort().map((d) => path.join(workspaceRoot, d));
|
|
190
|
+
}
|
|
136
191
|
/**
|
|
137
192
|
* PURE decision: should this pod be recycled as a stale-view zombie, and why? A pod qualifies only when it
|
|
138
193
|
* is a live, UP, gateway-spawned pod that is currently QUIET (0 in-flight AND idle for `settleMs`, so a busy
|
|
@@ -196,7 +251,7 @@ function createServiceLayer(rt, obs) {
|
|
|
196
251
|
* its whole devserver tree with it. One `ps` exec; a clean cold start is a no-op.
|
|
197
252
|
*/
|
|
198
253
|
const reapForeignRunners = (svc, target) => {
|
|
199
|
-
let out
|
|
254
|
+
let out;
|
|
200
255
|
try {
|
|
201
256
|
out = (0, node_child_process_1.execFileSync)('ps', ['ax', '-ww', '-o', 'pid=,pgid=,command='], { encoding: 'utf8', timeout: 5_000 });
|
|
202
257
|
}
|
|
@@ -300,6 +355,11 @@ function createServiceLayer(rt, obs) {
|
|
|
300
355
|
NX_ISOLATE_PLUGINS: 'false',
|
|
301
356
|
...(svc.wsKey ? { LENSMCP_WS_KEY: svc.wsKey } : {}),
|
|
302
357
|
LENSMCP_EVENT_FILE: svc.wsKey === rt.wsKey ? rt.eventFile : path.join(svc.root, '.lensmcp', 'events.jsonl'),
|
|
358
|
+
// Rides the env inherit down the whole nx chain (nx run → run-executor → serve fork) into
|
|
359
|
+
// main.devserver, whose gateway watchdog self-exits the pod tree when this pid dies. Without
|
|
360
|
+
// it an UNGRACEFUL gateway death (crash/SIGKILL — no process-group kill runs) orphans the
|
|
361
|
+
// entire chain under launchd forever (2026-07-28: a day-old tetros pod tree at PPID 1).
|
|
362
|
+
LENSMCP_GATEWAY_PID: String(process.pid),
|
|
303
363
|
...eastWestEnv(rt, svc.project),
|
|
304
364
|
},
|
|
305
365
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
@@ -530,23 +590,97 @@ function createServiceLayer(rt, obs) {
|
|
|
530
590
|
settleMs: types_1.POD_RECYCLE_SETTLE_MS, cooldownMs: types_1.POD_STALE_RECYCLE_COOLDOWN_MS,
|
|
531
591
|
};
|
|
532
592
|
let prevSig;
|
|
593
|
+
const prevScopedSig = new Map(); // bucket → its last signature
|
|
533
594
|
let scanInFlight = false;
|
|
534
595
|
let lastScanAt = 0;
|
|
535
|
-
|
|
536
|
-
|
|
596
|
+
/** The distinct top-level buckets owned by a gateway-managed project (services + `lens:true` apps) — every
|
|
597
|
+
* OTHER bucket is shared/leaf and belongs in every scope. Recomputed per scan so a workspace registered
|
|
598
|
+
* after boot is picked up. */
|
|
599
|
+
const managedBuckets = () => {
|
|
600
|
+
const roots = rt.projectRoots ?? {};
|
|
601
|
+
const names = new Set(rt.services.map((s) => s.project));
|
|
602
|
+
for (const r of rt.routes)
|
|
603
|
+
if (r.lens)
|
|
604
|
+
names.add(r.lens.project);
|
|
605
|
+
const buckets = new Set();
|
|
606
|
+
for (const n of names) {
|
|
607
|
+
const pr = roots[n];
|
|
608
|
+
if (!pr)
|
|
609
|
+
continue;
|
|
610
|
+
const seg = path.relative(rt.root, pr).split(path.sep).filter(Boolean)[0];
|
|
611
|
+
if (seg && !seg.startsWith('..'))
|
|
612
|
+
buckets.add(seg);
|
|
613
|
+
}
|
|
614
|
+
return [...buckets];
|
|
615
|
+
};
|
|
616
|
+
/** project → the absolute dirs its child must watch, or `undefined` when it cannot be narrowed (unknown
|
|
617
|
+
* project root / no `projectsConfigurations`) → that child keeps the workspace-wide clock. */
|
|
618
|
+
const scopeFor = (project, topLevel, managed) => {
|
|
619
|
+
const pr = rt.projectRoots?.[project];
|
|
620
|
+
if (!pr)
|
|
621
|
+
return undefined;
|
|
622
|
+
const dirs = sourceScopeDirs(rt.root, pr, managed, topLevel);
|
|
623
|
+
return dirs.length > 0 ? dirs : undefined;
|
|
624
|
+
};
|
|
625
|
+
// Kick a bounded, async source-set scan when due; on a SET change (file added/removed) stamp the clocks so
|
|
626
|
+
// children that predate it recycle. Non-blocking — the sweeper never awaits it. Two tiers: the
|
|
627
|
+
// workspace-WIDE signature (the fallback + back-compat clock) and one SCOPED signature per managed
|
|
628
|
+
// project's bucket, so a `server/**` add no longer recycles a `web/**` vite (see `sourceScopeDirs`). One
|
|
629
|
+
// scan per bucket, not per project — sibling projects in a bucket share a scope, so `web/apps/dashboard`
|
|
630
|
+
// and `web/apps/authentication` cost a single walk between them.
|
|
537
631
|
const maybeScanSourceSet = () => {
|
|
538
632
|
if (scanInFlight || Date.now() - lastScanAt < types_1.POD_STALE_SCAN_MS)
|
|
539
633
|
return;
|
|
540
634
|
scanInFlight = true;
|
|
541
635
|
lastScanAt = Date.now();
|
|
542
|
-
void
|
|
543
|
-
.
|
|
544
|
-
if (prevSig !== undefined &&
|
|
636
|
+
void (async () => {
|
|
637
|
+
const wide = await sourceSetSignature(rt.root);
|
|
638
|
+
if (prevSig !== undefined && wide !== prevSig) {
|
|
545
639
|
rt.sourceSetChangedAt = Date.now();
|
|
546
640
|
emit('info', 'source file set changed — stale pods recycle when idle', 'cluster-gateway', { kind: 'source-set-changed' });
|
|
547
641
|
}
|
|
548
|
-
prevSig =
|
|
549
|
-
|
|
642
|
+
prevSig = wide;
|
|
643
|
+
// Scoped tier. Skipped entirely without project roots (nothing to narrow by) — consumers then read
|
|
644
|
+
// the wide clock exactly as before.
|
|
645
|
+
if (!rt.projectRoots)
|
|
646
|
+
return;
|
|
647
|
+
let topLevel;
|
|
648
|
+
try {
|
|
649
|
+
topLevel = (await fs.promises.readdir(rt.root, { withFileTypes: true }))
|
|
650
|
+
.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
651
|
+
}
|
|
652
|
+
catch {
|
|
653
|
+
return;
|
|
654
|
+
}
|
|
655
|
+
const managed = managedBuckets();
|
|
656
|
+
const projects = new Set(rt.services.map((s) => s.project));
|
|
657
|
+
for (const r of rt.routes)
|
|
658
|
+
if (r.lens)
|
|
659
|
+
projects.add(r.lens.project);
|
|
660
|
+
// bucket → the scope dirs + the projects sharing it (one walk per bucket).
|
|
661
|
+
const byBucket = new Map();
|
|
662
|
+
for (const project of projects) {
|
|
663
|
+
const dirs = scopeFor(project, topLevel, managed);
|
|
664
|
+
if (!dirs)
|
|
665
|
+
continue;
|
|
666
|
+
const key = dirs.join('|');
|
|
667
|
+
const entry = byBucket.get(key) ?? { dirs, projects: [] };
|
|
668
|
+
entry.projects.push(project);
|
|
669
|
+
byBucket.set(key, entry);
|
|
670
|
+
}
|
|
671
|
+
const now = Date.now();
|
|
672
|
+
for (const [key, { dirs, projects: sharing }] of byBucket) {
|
|
673
|
+
const sig = await sourceSetSignature(rt.root, dirs);
|
|
674
|
+
const prev = prevScopedSig.get(key);
|
|
675
|
+
prevScopedSig.set(key, sig);
|
|
676
|
+
if (prev === undefined || sig === prev)
|
|
677
|
+
continue;
|
|
678
|
+
rt.sourceSetChangedFor ??= new Map();
|
|
679
|
+
for (const p of sharing)
|
|
680
|
+
rt.sourceSetChangedFor.set(p, now);
|
|
681
|
+
emit('info', `source file set changed in ${sharing.join(', ')}'s scope`, 'cluster-gateway', { kind: 'source-set-changed', scoped: true, projects: sharing });
|
|
682
|
+
}
|
|
683
|
+
})()
|
|
550
684
|
.catch(() => undefined)
|
|
551
685
|
.finally(() => { scanInFlight = false; });
|
|
552
686
|
};
|
|
@@ -590,7 +724,10 @@ function createServiceLayer(rt, obs) {
|
|
|
590
724
|
// stale — neither exit-respawn nor wedge-recycle sees it. Idle-gated in podRecycleReason so a busy
|
|
591
725
|
// pod is never interrupted.
|
|
592
726
|
if (live && !coldStarting && types_1.POD_RECYCLE_ENABLED) {
|
|
593
|
-
|
|
727
|
+
// Prefer this project's SCOPED clock (only the subtrees it can resolve); fall back to the
|
|
728
|
+
// workspace-wide one when the scan hasn't produced a scoped verdict for it.
|
|
729
|
+
const changedAt = rt.sourceSetChangedFor?.get(svc.project) ?? rt.sourceSetChangedAt ?? 0;
|
|
730
|
+
const reason = podRecycleReason(svc, Date.now(), changedAt, recycleCfg);
|
|
594
731
|
if (reason)
|
|
595
732
|
recyclePod(svc, reason);
|
|
596
733
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"observability.d.ts","sourceRoot":"","sources":["../../../../../../libs/cluster/src/executors/gateway/runtime/observability.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,KAAK,IAAI,MAAM,WAAW,CAAC;AACvC,OAAO,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"observability.d.ts","sourceRoot":"","sources":["../../../../../../libs/cluster/src/executors/gateway/runtime/observability.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,KAAK,IAAI,MAAM,WAAW,CAAC;AACvC,OAAO,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAoB9C,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;AAEpD;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,qBAAqB,CAAC;AAEzD,MAAM,WAAW,aAAa;IAC5B;;4GAEwG;IACxG,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvJ,GAAG,IAAI,MAAM,CAAC;IACd,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,GAAG,OAAO,GAAG,SAAS,CAAC;IAC3D,SAAS,CAAC,CAAC,EAAE,OAAO,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC1F,WAAW,CAAC,CAAC,EAAE,OAAO,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC5G,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5E,0FAA0F;IAC1F,gBAAgB,IAAI,MAAM,CAAC,OAAO,CAAC;CACpC;AAKD,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE;IAAE,cAAc,EAAE,MAAM,CAAA;CAAE,GAAG,aAAa,CAiHtG"}
|
|
@@ -17,6 +17,15 @@ const tslib_1 = require("tslib");
|
|
|
17
17
|
*/
|
|
18
18
|
const fs = tslib_1.__importStar(require("node:fs"));
|
|
19
19
|
const path = tslib_1.__importStar(require("node:path"));
|
|
20
|
+
const busHygiene = (() => {
|
|
21
|
+
try {
|
|
22
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
23
|
+
return require('@lensmcp/node-instrumentation');
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
})();
|
|
20
29
|
/**
|
|
21
30
|
* The lens's OWN dashboard route project (the value `lens-children.ts` gives the `lensmcp.local/<key>/`
|
|
22
31
|
* route). Traffic to it is the lens UI polling its own control-plane API (`/<key>/api/cluster|logs|snapshot`)
|
|
@@ -29,15 +38,28 @@ exports.LENS_DASHBOARD_PROJECT = '(lens-dashboard)';
|
|
|
29
38
|
const hdr = (v) => typeof v === 'string' && v !== '' ? v : Array.isArray(v) ? v[0] : undefined;
|
|
30
39
|
function createObservability(eventFile, opts) {
|
|
31
40
|
const eid = () => Date.now().toString(36) + Math.random().toString(36).slice(2, 12);
|
|
41
|
+
// The gateway narrates OTHER apps' traffic — an app stuck in a retry loop must not turn that
|
|
42
|
+
// narration into a bus flood (2026-07-28: `gateway-request:<project>` alone wrote thousands of
|
|
43
|
+
// lines/min). Per-fingerprint token bucket: first burst passes, then a trickle carrying
|
|
44
|
+
// `floodSuppressed` counts. Errors stay loud — the burst re-arms once the storm subsides.
|
|
45
|
+
const floodGuard = busHygiene?.createEventFloodGuard({ burst: 30, perSec: 5 });
|
|
32
46
|
const emit = (severity, title, fingerprint, raw, flowCtx, busFile) => {
|
|
33
47
|
const target = busFile ?? eventFile; // a registered workspace's service events go to ITS bus, not the daemon's
|
|
34
48
|
try {
|
|
49
|
+
const admit = floodGuard ? floodGuard.admit(fingerprint) : { ok: true, suppressed: 0 };
|
|
50
|
+
if (!admit.ok)
|
|
51
|
+
return;
|
|
35
52
|
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
36
|
-
|
|
53
|
+
const line = JSON.stringify({
|
|
37
54
|
id: eid(), sessionId: 'pending', timestamp: Date.now(),
|
|
38
55
|
source: 'gateway', category: 'cluster', severity,
|
|
39
|
-
context: { sessionId: 'pending', ...flowCtx }, fingerprint, title,
|
|
40
|
-
|
|
56
|
+
context: { sessionId: 'pending', ...flowCtx }, fingerprint, title,
|
|
57
|
+
raw: admit.suppressed > 0 ? { ...raw, floodSuppressed: admit.suppressed } : raw,
|
|
58
|
+
}) + '\n';
|
|
59
|
+
// The gateway was the one bus writer with NO size cap — enforce the same rotation contract
|
|
60
|
+
// as every other producer (emit.ts / capture-runner), per target file.
|
|
61
|
+
busHygiene?.maybeRotateEventFile(target, line.length);
|
|
62
|
+
fs.appendFileSync(target, line);
|
|
41
63
|
}
|
|
42
64
|
catch { /* lens offline — never block traffic */ }
|
|
43
65
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../../../../libs/cluster/src/executors/gateway/runtime/server.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAkB,KAAK,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AAK/D,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAkB,qBAAqB,EAAe,KAAK,EAAE,MAAM,SAAS,CAAC;AA0BxH;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,KAAK,EAAE,GAAG,gBAAgB,CA4ChF;AAED;mGACmG;AACnG,eAAO,MAAM,oBAAoB,EAAE,WAAW,CAAC,MAAM,CAA8E,CAAC;AAkBpI,wBAAsB,YAAY,CAChC,OAAO,EAAE,qBAAqB,EAC9B,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,aAAa,CAAC,
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../../../../libs/cluster/src/executors/gateway/runtime/server.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAkB,KAAK,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AAK/D,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAkB,qBAAqB,EAAe,KAAK,EAAE,MAAM,SAAS,CAAC;AA0BxH;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,KAAK,EAAE,GAAG,gBAAgB,CA4ChF;AAED;mGACmG;AACnG,eAAO,MAAM,oBAAoB,EAAE,WAAW,CAAC,MAAM,CAA8E,CAAC;AAkBpI,wBAAsB,YAAY,CAChC,OAAO,EAAE,qBAAqB,EAC9B,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,aAAa,CAAC,CAqSxB"}
|
|
@@ -193,6 +193,11 @@ async function startGateway(options, context) {
|
|
|
193
193
|
sweepMs,
|
|
194
194
|
trafficFlushMs,
|
|
195
195
|
https,
|
|
196
|
+
// Absolute project root per project name — the scanner narrows each child's staleness scope with it
|
|
197
|
+
// (`sourceScopeDirs`), so a `server/**` file add stops recycling every `web/**` vite. Absent (a bare
|
|
198
|
+
// context with no projectsConfigurations) ⇒ the workspace-wide clock, i.e. previous behavior.
|
|
199
|
+
projectRoots: Object.fromEntries(Object.entries(context.projectsConfigurations?.projects ?? {})
|
|
200
|
+
.map(([name, cfg]) => [name, path.resolve(context.root, cfg.root)])),
|
|
196
201
|
stopped: () => stopped,
|
|
197
202
|
};
|
|
198
203
|
// --- layers -----------------------------------------------------------------
|
|
@@ -279,6 +279,16 @@ export interface GatewayRuntime {
|
|
|
279
279
|
* lens-frontend sweeper (lens-children) — recycle any child that spawned before it. `0`/undefined until
|
|
280
280
|
* the first change is observed. Mutable (the one non-readonly runtime field, written only by the scanner). */
|
|
281
281
|
sourceSetChangedAt?: number;
|
|
282
|
+
/** Per-PROJECT scoped twin of {@link sourceSetChangedAt}: the last time the file set changed *within the
|
|
283
|
+
* subtrees that project could actually resolve* (`sourceScopeDirs`). The workspace-wide clock above
|
|
284
|
+
* recycles every child for an add ANYWHERE — so a backend-only `.ts` restarted every frontend vite. A
|
|
285
|
+
* consumer prefers its own entry and falls back to the wide clock when absent (project root unknown, or
|
|
286
|
+
* the scan not yet warmed). Mutable, written only by the scanner. */
|
|
287
|
+
sourceSetChangedFor?: Map<string, number>;
|
|
288
|
+
/** Absolute project root per project name (from `projectsConfigurations`) — lets the scanner derive each
|
|
289
|
+
* child's watch scope, and tells it which top-level buckets are OWNED by a managed project. Absent ⇒
|
|
290
|
+
* every consumer falls back to the workspace-wide clock (previous behavior). */
|
|
291
|
+
readonly projectRoots?: Readonly<Record<string, string>>;
|
|
282
292
|
/** Teardown flag — a GETTER, never a captured boolean, so every layer reads
|
|
283
293
|
* the LIVE value (an in-flight cold start / auto-heal must not act after stop). */
|
|
284
294
|
stopped(): boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../../libs/cluster/src/executors/gateway/runtime/types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../../libs/cluster/src/executors/gateway/runtime/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,9 +7,23 @@ export interface WorkspaceEntry {
|
|
|
7
7
|
base: string;
|
|
8
8
|
/** The gateway process that registered this workspace (owns :443 for it). Liveness is checked via this. */
|
|
9
9
|
pid: number;
|
|
10
|
+
/**
|
|
11
|
+
* The registering process's start-time stamp (`ps -o lstart=`), captured at register. A pid alone
|
|
12
|
+
* can LIE: after an ungraceful gateway death the OS recycles the number, and `kill(pid, 0)` then
|
|
13
|
+
* vouches for a stranger (2026-07-28: tetros's dead-gateway pid came back as an nx run-executor and
|
|
14
|
+
* the chooser kept listing the workspace as live). Same pid + same start time = same process.
|
|
15
|
+
* Absent on legacy entries and on platforms without `ps` — liveness then falls back to kill(0).
|
|
16
|
+
*/
|
|
17
|
+
procStamp?: string;
|
|
10
18
|
/** ISO timestamp of the last register. */
|
|
11
19
|
updatedAt: string;
|
|
12
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* The start-time identity stamp for a pid (`''` when `ps` is unavailable — Windows, restricted
|
|
23
|
+
* environments — or the process is gone). Start time is immutable for the life of a process and
|
|
24
|
+
* survives in no recycled successor, which makes it the cheapest cross-platform-ish identity proof.
|
|
25
|
+
*/
|
|
26
|
+
export declare function processStamp(pid: number): string;
|
|
13
27
|
/** `~/.lensmcp/workspaces.json` — override the home dir via `LENSMCP_HOME` (tests). */
|
|
14
28
|
export declare function registryPath(): string;
|
|
15
29
|
export declare function readWorkspaces(file?: string): WorkspaceEntry[];
|
|
@@ -17,6 +31,10 @@ export declare function readWorkspaces(file?: string): WorkspaceEntry[];
|
|
|
17
31
|
export declare function registerWorkspace(entry: WorkspaceEntry, file?: string): void;
|
|
18
32
|
/** Drop this workspace — called on a graceful gateway stop. */
|
|
19
33
|
export declare function unregisterWorkspace(key: string, file?: string): void;
|
|
20
|
-
/**
|
|
21
|
-
|
|
34
|
+
/**
|
|
35
|
+
* Is the gateway that registered this workspace still alive? `process.kill(pid, 0)` throws ESRCH if
|
|
36
|
+
* not — and when the entry carries a `procStamp`, the pid must ALSO still be the SAME process
|
|
37
|
+
* (recycled pids fail the start-time comparison instead of impersonating a live gateway).
|
|
38
|
+
*/
|
|
39
|
+
export declare function isWorkspaceLive(entry: Pick<WorkspaceEntry, 'pid' | 'procStamp'>): boolean;
|
|
22
40
|
//# sourceMappingURL=workspace-registry.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace-registry.d.ts","sourceRoot":"","sources":["../../../../../../libs/cluster/src/executors/gateway/runtime/workspace-registry.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"workspace-registry.d.ts","sourceRoot":"","sources":["../../../../../../libs/cluster/src/executors/gateway/runtime/workspace-registry.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,cAAc;IAC7B,4FAA4F;IAC5F,GAAG,EAAE,MAAM,CAAC;IACZ,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,sEAAsE;IACtE,IAAI,EAAE,MAAM,CAAC;IACb,2GAA2G;IAC3G,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0CAA0C;IAC1C,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAWhD;AAED,uFAAuF;AACvF,wBAAgB,YAAY,IAAI,MAAM,CAGrC;AAED,wBAAgB,cAAc,CAAC,IAAI,SAAiB,GAAG,cAAc,EAAE,CAYtE;AAWD,wEAAwE;AACxE,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,cAAc,EAAE,IAAI,SAAiB,GAAG,IAAI,CAKpF;AAED,+DAA+D;AAC/D,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,SAAiB,GAAG,IAAI,CAK5E;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,cAAc,EAAE,KAAK,GAAG,WAAW,CAAC,GAAG,OAAO,CAUzF"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.processStamp = processStamp;
|
|
3
4
|
exports.registryPath = registryPath;
|
|
4
5
|
exports.readWorkspaces = readWorkspaces;
|
|
5
6
|
exports.registerWorkspace = registerWorkspace;
|
|
@@ -16,9 +17,29 @@ const tslib_1 = require("tslib");
|
|
|
16
17
|
* Concurrency: read-modify-write, best-effort. Writes are rare (start/stop only) and the file is tiny, so
|
|
17
18
|
* a lost update at most drops one entry from the listing until the next start — never a correctness issue.
|
|
18
19
|
*/
|
|
20
|
+
const node_child_process_1 = require("node:child_process");
|
|
19
21
|
const fs = tslib_1.__importStar(require("node:fs"));
|
|
20
22
|
const os = tslib_1.__importStar(require("node:os"));
|
|
21
23
|
const path = tslib_1.__importStar(require("node:path"));
|
|
24
|
+
/**
|
|
25
|
+
* The start-time identity stamp for a pid (`''` when `ps` is unavailable — Windows, restricted
|
|
26
|
+
* environments — or the process is gone). Start time is immutable for the life of a process and
|
|
27
|
+
* survives in no recycled successor, which makes it the cheapest cross-platform-ish identity proof.
|
|
28
|
+
*/
|
|
29
|
+
function processStamp(pid) {
|
|
30
|
+
if (!pid || pid <= 0 || process.platform === 'win32')
|
|
31
|
+
return '';
|
|
32
|
+
try {
|
|
33
|
+
return (0, node_child_process_1.execFileSync)('ps', ['-p', String(pid), '-o', 'lstart='], {
|
|
34
|
+
encoding: 'utf8',
|
|
35
|
+
timeout: 2_000,
|
|
36
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
37
|
+
}).trim();
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return '';
|
|
41
|
+
}
|
|
42
|
+
}
|
|
22
43
|
/** `~/.lensmcp/workspaces.json` — override the home dir via `LENSMCP_HOME` (tests). */
|
|
23
44
|
function registryPath() {
|
|
24
45
|
const home = process.env['LENSMCP_HOME'] || os.homedir();
|
|
@@ -56,15 +77,23 @@ function registerWorkspace(entry, file = registryPath()) {
|
|
|
56
77
|
function unregisterWorkspace(key, file = registryPath()) {
|
|
57
78
|
writeWorkspaces(readWorkspaces(file).filter((e) => e.key !== key), file);
|
|
58
79
|
}
|
|
59
|
-
/**
|
|
80
|
+
/**
|
|
81
|
+
* Is the gateway that registered this workspace still alive? `process.kill(pid, 0)` throws ESRCH if
|
|
82
|
+
* not — and when the entry carries a `procStamp`, the pid must ALSO still be the SAME process
|
|
83
|
+
* (recycled pids fail the start-time comparison instead of impersonating a live gateway).
|
|
84
|
+
*/
|
|
60
85
|
function isWorkspaceLive(entry) {
|
|
61
86
|
if (!entry.pid || entry.pid <= 0)
|
|
62
87
|
return false;
|
|
63
88
|
try {
|
|
64
89
|
process.kill(entry.pid, 0);
|
|
65
|
-
return true; // alive (or EPERM below — exists but not ours)
|
|
66
90
|
}
|
|
67
91
|
catch (e) {
|
|
68
|
-
|
|
92
|
+
if (e.code !== 'EPERM')
|
|
93
|
+
return false; // EPERM = exists but not signalable; ESRCH = gone
|
|
69
94
|
}
|
|
95
|
+
if (!entry.procStamp)
|
|
96
|
+
return true; // legacy entry / no-ps platform — pid liveness is all we have
|
|
97
|
+
const now = processStamp(entry.pid);
|
|
98
|
+
return now === '' ? true : now === entry.procStamp; // '' = ps unavailable here — don't false-negative
|
|
70
99
|
}
|
package/main.devserver.js
CHANGED
|
@@ -1090,5 +1090,28 @@ else {
|
|
|
1090
1090
|
setTimeout(() => process.exit(0), 700).unref();
|
|
1091
1091
|
};
|
|
1092
1092
|
['SIGINT', 'SIGTERM', 'SIGHUP', 'SIGQUIT', 'SIGUSR2'].forEach(sig => process.on(sig, () => void shutdown(sig)));
|
|
1093
|
+
// Gateway watchdog: the gateway kills pods via its spawned process group, but an UNGRACEFUL
|
|
1094
|
+
// gateway death (crash/SIGKILL) never runs that kill — the whole nx run → run-executor →
|
|
1095
|
+
// devserver chain reparents to launchd and squats its ports/sockets forever (the 2026-07-28
|
|
1096
|
+
// day-old orphan tree). We are layers below the gateway, so a ppid check can't see it — poll
|
|
1097
|
+
// the stamped pid instead and tear down through the SAME graceful path when it's gone. The
|
|
1098
|
+
// chain above us unwinds as our exit propagates. A pod run OUTSIDE a gateway (`nx serve`
|
|
1099
|
+
// directly) has no LENSMCP_GATEWAY_PID and is untouched.
|
|
1100
|
+
const gatewayPid = Number(process.env.LENSMCP_GATEWAY_PID ?? 0);
|
|
1101
|
+
if (Number.isInteger(gatewayPid) && gatewayPid > 0) {
|
|
1102
|
+
const watchdog = setInterval(() => {
|
|
1103
|
+
try {
|
|
1104
|
+
process.kill(gatewayPid, 0);
|
|
1105
|
+
}
|
|
1106
|
+
catch (e) {
|
|
1107
|
+
if (e.code === 'EPERM')
|
|
1108
|
+
return; // exists, just not signalable
|
|
1109
|
+
clearInterval(watchdog);
|
|
1110
|
+
console.error(`[parent] gateway (pid ${gatewayPid}) is gone — shutting the pod down to avoid an orphan tree.`);
|
|
1111
|
+
void shutdown('gateway-gone');
|
|
1112
|
+
}
|
|
1113
|
+
}, 5_000);
|
|
1114
|
+
watchdog.unref(); // never keeps an otherwise-done parent alive
|
|
1115
|
+
}
|
|
1093
1116
|
})();
|
|
1094
1117
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lensmcp/cluster",
|
|
3
|
-
"version": "1.16.
|
|
3
|
+
"version": "1.16.33",
|
|
4
4
|
"description": "Run your Nx workspace as a local production cluster: pods on unix sockets with true HMR, one https gateway with per-project domains, scale-from-zero, autoscale, idle-kill, local-CA TLS — observed by the LensMCP lens.",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"types": "./index.d.ts",
|
|
@@ -65,8 +65,8 @@
|
|
|
65
65
|
}
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
|
-
"@lensmcp/node-instrumentation": "1.16.
|
|
69
|
-
"@lensmcp/nx-plugin": "1.16.
|
|
68
|
+
"@lensmcp/node-instrumentation": "1.16.33",
|
|
69
|
+
"@lensmcp/nx-plugin": "1.16.33",
|
|
70
70
|
"fork-ts-checker-webpack-plugin": "^9.0.0",
|
|
71
71
|
"glob": "^11.0.0",
|
|
72
72
|
"http-proxy": "^1.18.0",
|