@north-light/crouter 0.3.168 → 0.3.169
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/cli.js +4 -0
- package/dist/clients/attach/viewer.js +236 -236
- package/dist/commands/sys/daemon.js +1 -0
- package/dist/core/__tests__/revive.test.js +48 -0
- package/dist/core/bash-jobs.d.ts +16 -17
- package/dist/core/bash-jobs.js +39 -38
- package/dist/core/canvas/__tests__/render-remote.test.js +25 -0
- package/dist/core/canvas/crons.d.ts +3 -2
- package/dist/core/canvas/crons.js +3 -2
- package/dist/core/canvas/render-source.js +6 -2
- package/dist/core/runtime/revive-all.js +3 -1
- package/dist/core/runtime/revive.d.ts +7 -0
- package/dist/core/runtime/revive.js +15 -3
- package/dist/daemon/fleet.js +4 -0
- package/dist/pi-extensions/canvas-bash-valve.js +76 -18
- package/package.json +1 -1
- package/runtime.lock.json +2 -2
- package/scripts/install-runtime.mjs +36 -13
|
@@ -25,6 +25,17 @@ function run(command, args, cwd, capture = false, env = process.env) {
|
|
|
25
25
|
});
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
/** Capture a probe's stdout even when a candidate process exits during the probe. */
|
|
29
|
+
function probe(command, args, cwd) {
|
|
30
|
+
return new Promise((resolveRun) => {
|
|
31
|
+
const child = spawn(command, args, { cwd, stdio: ['ignore', 'pipe', 'ignore'] });
|
|
32
|
+
let output = '';
|
|
33
|
+
child.stdout.on('data', (chunk) => { output += chunk; });
|
|
34
|
+
child.on('error', () => resolveRun(output));
|
|
35
|
+
child.on('exit', () => resolveRun(output));
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
28
39
|
function digest(value) {
|
|
29
40
|
return createHash('sha256').update(value).digest('hex');
|
|
30
41
|
}
|
|
@@ -146,32 +157,44 @@ async function pack(archiveDir) {
|
|
|
146
157
|
return join(archiveDir, packed[0].filename);
|
|
147
158
|
}
|
|
148
159
|
|
|
160
|
+
/** Generation ids named anywhere in a `ps` or `lsof` dump. */
|
|
149
161
|
function generationIdsIn(text) {
|
|
150
|
-
return [...text.matchAll(/generations\/([a-f0-9]{64})(
|
|
162
|
+
return [...text.matchAll(/generations\/([a-f0-9]{64})(?:[/\s]|$)/g)].map((match) => match[1]);
|
|
151
163
|
}
|
|
152
164
|
|
|
165
|
+
/** Return every generation used by a running process and whether every stable
|
|
166
|
+
* selector process exposed its generation lease. */
|
|
153
167
|
async function liveGenerationIds() {
|
|
154
168
|
const output = await run('ps', ['-axww', '-o', 'pid=,command='], RUNTIME_HOME, true);
|
|
155
169
|
const live = new Set(generationIdsIn(output));
|
|
156
170
|
const nodePids = [];
|
|
157
|
-
|
|
171
|
+
const opaqueStablePids = new Set();
|
|
158
172
|
for (const line of output.split('\n')) {
|
|
159
173
|
const match = /^\s*(\d+)\s+(.*)$/.exec(line);
|
|
160
174
|
if (!match) continue;
|
|
161
175
|
const [, pid, command] = match;
|
|
162
|
-
|
|
176
|
+
const stableSelector = /^(?:\S*node\s+)?\S*\/bin\/(?:crtr|crtrd|crouter)(?:\s|$)/.test(command);
|
|
177
|
+
if (stableSelector && generationIdsIn(command).length === 0) opaqueStablePids.add(pid);
|
|
163
178
|
if (/(?:^|[\s/])(?:node|crtrd?|crouter)(?:[\s]|$)/.test(command)) nodePids.push(pid);
|
|
164
179
|
}
|
|
165
|
-
|
|
166
|
-
// minutes resolving process cwd values that cannot change that decision.
|
|
167
|
-
if (uncertain || nodePids.length === 0) return { live, uncertain };
|
|
180
|
+
if (nodePids.length === 0) return { live, uncertain: opaqueStablePids.size > 0 };
|
|
168
181
|
|
|
169
|
-
//
|
|
170
|
-
//
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
const
|
|
174
|
-
for (const
|
|
182
|
+
// One lsof invocation resolves cwd references and the runtime entry-file
|
|
183
|
+
// lease held by each stable CLI process without a per-process startup penalty.
|
|
184
|
+
const open = await probe('lsof', ['-n', '-P', '-a', '-p', nodePids.join(','), '-Fn'], RUNTIME_HOME);
|
|
185
|
+
let pid;
|
|
186
|
+
const exposedStablePids = new Set();
|
|
187
|
+
for (const line of open.split('\n')) {
|
|
188
|
+
const processMatch = /^p(\d+)$/.exec(line);
|
|
189
|
+
if (processMatch) {
|
|
190
|
+
pid = processMatch[1];
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
const ids = generationIdsIn(line);
|
|
194
|
+
for (const id of ids) live.add(id);
|
|
195
|
+
if (pid !== undefined && ids.length > 0 && opaqueStablePids.has(pid)) exposedStablePids.add(pid);
|
|
196
|
+
}
|
|
197
|
+
const uncertain = [...opaqueStablePids].some((stablePid) => !exposedStablePids.has(stablePid));
|
|
175
198
|
return { live, uncertain };
|
|
176
199
|
}
|
|
177
200
|
|
|
@@ -186,7 +209,7 @@ async function pruneGenerations() {
|
|
|
186
209
|
const selected = await selectedGenerationId();
|
|
187
210
|
const { live, uncertain } = await liveGenerationIds();
|
|
188
211
|
if (uncertain) {
|
|
189
|
-
process.stderr.write('runtime generation GC skipped: a live stable crouter shim does not expose its generation
|
|
212
|
+
process.stderr.write('runtime generation GC skipped: a live stable crouter shim does not expose its generation lease\n');
|
|
190
213
|
return;
|
|
191
214
|
}
|
|
192
215
|
const entries = await readdir(GENERATIONS, { withFileTypes: true });
|