Skip to content

Commit 5100a71

Browse files
authored
Merge pull request #94 from gadget-inc/parent-crash-monitoring
Make zombie children clean themselves up
2 parents 8f60ee6 + 46309fa commit 5100a71

File tree

27 files changed

+334
-2
lines changed

27 files changed

+334
-2
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
- uses: actions/checkout@v2
1414
- uses: ./.github/actions/setup-test-env
1515
- run: pnpm build
16-
- run: test/test.sh
16+
- run: integration-test/test.sh
1717
- run: pnpm jest
1818

1919
lint:
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"name": "parent-crash",
3+
"version": "1.0.0",
4+
"description": "",
5+
"main": "index.js",
6+
"scripts": {
7+
"test": "echo \"Error: no test specified\" && exit 1"
8+
},
9+
"license": "ISC"
10+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
process.stderr.write("child started\n")
2+
setInterval(() => {
3+
process.stderr.write("child still alive\n")
4+
}, 200)
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#!/usr/bin/env zx
2+
const assert = require("assert");
3+
const { exec } = require("child_process");
4+
5+
async function getChildPids(parentPid, callback) {
6+
const result = await $`pgrep -P ${parentPid}`;
7+
return result.stdout
8+
.split("\n")
9+
.filter((pid) => pid)
10+
.map((pid) => parseInt(pid, 10));
11+
}
12+
13+
function processIsRunning(pid) {
14+
try {
15+
process.kill(pid, 0);
16+
return true;
17+
} catch (e) {
18+
return false;
19+
}
20+
}
21+
22+
const { setTimeout } = require("timers/promises");
23+
24+
const main = async () => {
25+
// launch the wds process
26+
const parent = $`${__dirname}/../../pkg/wds.bin.js --watch ${__dirname}/run.ts`.nothrow();
27+
28+
// wait for the wds process to start
29+
await setTimeout(500);
30+
31+
// get the pid of the child process that the parent wds supervisor will have started
32+
const pids = await getChildPids(parent.child.pid);
33+
assert(pids.length > 0, "no child pids found for supervisor process");
34+
35+
// SIGKILL the parent process, as if it OOMed or something like that to simulate a zombie child
36+
console.log(`killing parent (${parent.child.pid})`);
37+
await parent.kill(9);
38+
assert.ok(processIsRunning(pids[0]), "test is broken, child process is not running immediately after parent is dead");
39+
40+
// ensure the children are dead too after their monitoring delay
41+
await setTimeout(3000);
42+
43+
for (const pid of pids) {
44+
assert.ok(!processIsRunning(pid), `child process ${pid} is still running after parent has been killed`);
45+
}
46+
47+
await parent;
48+
};
49+
50+
void main();
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
const http = require("http");
2+
3+
const requestListener = function (req, res) {
4+
res.writeHead(200);
5+
res.end("Hey, Pluto!");
6+
};
7+
8+
const server = http.createServer(requestListener);
9+
server.listen(8080);
10+
console.warn("Listening on 8080");

0 commit comments

Comments
 (0)