@ai-ecoverse/slicc-shared-web 1.10.2 → 1.10.3

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/README.md CHANGED
@@ -99,8 +99,8 @@ Why it works the way it does:
99
99
  ## Cleanup
100
100
 
101
101
  `close()` stops Chrome and removes its profile. It asks Chrome to close, waits up to 10 s for the exit, sends `SIGKILL`, waits up to 5 s more and then moves on with a warning, so a browser that ignores `Browser.close` or a missed exit never hangs teardown. A test process that ends without `close()` still leaves nothing running:
102
- - on `exit` and on `SIGINT`, `SIGTERM` or `SIGHUP`, the harness kills every browser it started in that process with `SIGKILL` and removes its profile and crash dump directory, then re-raises the signal so the process ends the way it would have;
103
- - when the test process dies of `SIGKILL`, no handler runs. A watchdog, a `sh` that reads a pipe from the test process, then gets end of file and kills Chrome with `SIGKILL` at once. Chrome also shuts itself down when the CDP pipe closes, but that can take seconds. Only the profile stays behind;
102
+ - on `exit` and on `SIGINT`, `SIGTERM` or `SIGHUP`, the harness kills every browser it started in that process, with all its helper processes (Chrome runs in its own process group), with `SIGKILL` and removes its profile and crash dump directory, then re-raises the signal so the process ends the way it would have;
103
+ - when the test process dies of `SIGKILL`, no handler runs. A watchdog, a `sh` in its own process group that reads a pipe from the test process, then gets end of file and kills Chrome's process group with `SIGKILL` at once. Chrome also shuts itself down when the CDP pipe closes, but that can take seconds. Only the profile stays behind;
104
104
  - the first `launch()` in a process removes every `slicc-harness-*` directory in `$TMPDIR` that is older than a day, or older than a minute and no running process uses as its `--user-data-dir`. It never kills a process.
105
105
 
106
106
  ## Crash dumps
@@ -74,6 +74,7 @@ export async function start(
74
74
  ) {
75
75
  const child = spawn(executable, args, {
76
76
  env,
77
+ detached: true,
77
78
  stdio: ['ignore', 'ignore', 'pipe', 'pipe', 'pipe'],
78
79
  });
79
80
  const stderr = lines(child.stderr);
@@ -111,7 +112,7 @@ export async function stop(cdp, child, waits = WAITS) {
111
112
  await bounded(cdp.send('Browser.close').catch(ignore), 'Browser.close', waits.close);
112
113
  cdp.close();
113
114
  if (gone() || (await bounded(exited, 'exit', waits.exit)) !== TIMED_OUT || gone()) return;
114
- child.kill('SIGKILL');
115
+ kill(child);
115
116
  if (gone() || (await bounded(exited, 'exit after SIGKILL', waits.kill)) !== TIMED_OUT) return;
116
117
  if (!gone()) console.warn(`chrome: pid ${child.pid} still runs after SIGKILL, moving on`);
117
118
  }
@@ -123,15 +124,27 @@ export const GRACE = 60 * 1000;
123
124
  const signals = ['SIGINT', 'SIGTERM', 'SIGHUP'];
124
125
  const running = new Set();
125
126
 
126
- function kill(child) {
127
+ export function kill(child) {
128
+ if (child.pid > 0 && child.spawnargs?.length) {
129
+ try {
130
+ process.kill(-child.pid, 'SIGKILL');
131
+ } catch {}
132
+ }
127
133
  if (child.exitCode === null && child.signalCode === null) child.kill('SIGKILL');
128
134
  }
129
135
 
130
- function reap() {
131
- for (const { children, paths } of running) {
132
- for (const child of children) kill(child);
136
+ function remove(entries) {
137
+ for (const { paths } of entries) {
133
138
  for (const path of paths) rmSync(path, { recursive: true, force: true });
134
139
  }
140
+ }
141
+
142
+ function reap() {
143
+ const entries = [...running];
144
+ for (const { children } of entries) children.forEach(kill);
145
+ remove(entries);
146
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 200);
147
+ remove(entries);
135
148
  running.clear();
136
149
  unhook();
137
150
  }
@@ -152,7 +165,8 @@ function unhook() {
152
165
  }
153
166
 
154
167
  export function watchdog(pid) {
155
- const dog = spawn('sh', ['-c', 'read -r _; kill -9 "$0" 2>/dev/null', String(pid)], {
168
+ const dog = spawn('sh', ['-c', 'read -r _; kill -9 -"$0" "$0" 2>/dev/null', String(pid)], {
169
+ detached: true,
156
170
  stdio: ['pipe', 'ignore', 'ignore'],
157
171
  });
158
172
  dog.on('error', ignore);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-ecoverse/slicc-shared-web",
3
- "version": "1.10.2",
3
+ "version": "1.10.3",
4
4
  "description": "Shared Renovate, Biome, TypeScript, lefthook and GitHub Actions configuration, plus the CDP integration-test harness, for SLICC's web repos",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",