Skip to content

Commit 384e5b1

Browse files
Ensure project_eval result is received by the parent (#45)
Currently the child does `process.send` and immediately `process.exit`. My understanding is that `process.send` is async and it is not guaranteed that the message is sent by the time the child exists. To guarantee it, we make the parent send an acknowledgement before exiting. See nodejs/node#6767.
1 parent 97d1746 commit 384e5b1

2 files changed

Lines changed: 31 additions & 19 deletions

File tree

src/evaluation/code_executor.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ export async function executeIsolated(request: EvaluationRequest): Promise<Evalu
3232
const { data, success } = msg;
3333
evaluation.result = data;
3434
evaluation.success = success;
35+
// Acknowledge the result and tell the child to exit gracefully.
36+
child.send({ type: 'finish' });
3537
}
3638
});
3739

@@ -58,6 +60,6 @@ export async function executeIsolated(request: EvaluationRequest): Promise<Evalu
5860

5961
child.on('exit', () => clearTimeout(timeoutId));
6062

61-
child.send(request);
63+
child.send({ type: 'evaluate', request: request });
6264
});
6365
}

src/evaluation/eval_worker.ts

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,38 @@
11
import type { EvaluationRequest } from '../core';
22

3-
process.on('message', async ({ code, args }: EvaluationRequest) => {
3+
type WorkerMessage = { type: 'evaluate'; request: EvaluationRequest } | { type: 'finish' };
4+
5+
process.on('message', async (message: WorkerMessage) => {
46
if (!process.send) {
57
console.error('[Tidewave] Unable to establish communication channel with code-executor.');
68
process.exit(1);
79
}
810

9-
try {
10-
const AsyncFunction = Object.getPrototypeOf(async () => {}).constructor;
11-
const fn = new AsyncFunction(code);
12-
const result = await fn(...args);
11+
if (message.type === 'evaluate') {
12+
const { code, args } = message.request;
1313

14-
process.send({
15-
type: 'result',
16-
success: true,
17-
data: (result ?? null) && result,
18-
});
19-
} catch (error) {
20-
process.send({
21-
type: 'result',
22-
success: false,
23-
data: new String(error),
24-
});
25-
}
14+
try {
15+
const AsyncFunction = Object.getPrototypeOf(async () => {}).constructor;
16+
const fn = new AsyncFunction(code);
17+
const result = await fn(...args);
2618

27-
process.exit(0);
19+
process.send({
20+
type: 'result',
21+
success: true,
22+
data: (result ?? null) && result,
23+
});
24+
} catch (error) {
25+
process.send({
26+
type: 'result',
27+
success: false,
28+
data: new String(error),
29+
});
30+
}
31+
} else if (message.type === 'finish') {
32+
// Note that process.send is async [1], so we wait for the parent
33+
// to receive the result and then tell us to exit.
34+
//
35+
// [1]: https://github.com/nodejs/node/issues/6767
36+
process.exit(0);
37+
}
2838
});

0 commit comments

Comments
 (0)