Skip to content

Commit 9c72258

Browse files
authored
fix(sandbox): ensure non-bullmq messages are ignored (#3704) fixes #3703
1 parent cce160d commit 9c72258

File tree

4 files changed

+95
-0
lines changed

4 files changed

+95
-0
lines changed

src/classes/child.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,10 @@ export class Child extends EventEmitter {
175175
private async initChild() {
176176
const onComplete = new Promise<void>((resolve, reject) => {
177177
const onMessageHandler = (msg: any) => {
178+
if (!Object.values(ParentCommand).includes(msg.cmd)) {
179+
return;
180+
}
181+
178182
if (msg.cmd === ParentCommand.InitCompleted) {
179183
resolve();
180184
} else if (msg.cmd === ParentCommand.InitFailed) {
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/**
2+
* Custom main file that sends non-BullMQ messages during initialization
3+
* to test that the child process properly ignores them.
4+
*/
5+
'use strict';
6+
7+
const { ChildProcessor } = require('../../dist/cjs/classes/child-processor');
8+
const { ParentCommand, ChildCommand } = require('../../dist/cjs/enums');
9+
const { errorToJSON, toString } = require('../../dist/cjs/utils');
10+
11+
const send = async msg => {
12+
if (process.send) {
13+
return new Promise((resolve, reject) => {
14+
process.send(msg, err => {
15+
if (err) {
16+
reject(err);
17+
} else {
18+
resolve();
19+
}
20+
});
21+
});
22+
}
23+
};
24+
25+
const childProcessor = new ChildProcessor(send, process);
26+
27+
process.on('message', async msg => {
28+
try {
29+
switch (msg.cmd) {
30+
case ChildCommand.Init:
31+
// Send non-BullMQ messages before initialization
32+
await send({ type: 'debug', message: 'Starting initialization' });
33+
await send({ randomKey: 'randomValue' });
34+
await send({ cmd: 'INVALID_COMMAND' });
35+
await send({ cmd: 999 });
36+
37+
// Now do the actual initialization
38+
await childProcessor.init(msg.value);
39+
break;
40+
case ChildCommand.Start:
41+
await childProcessor.start(msg.job, msg?.token);
42+
break;
43+
case ChildCommand.Stop:
44+
break;
45+
}
46+
} catch (err) {
47+
console.error('Error handling child message');
48+
}
49+
});
50+
51+
process.on('SIGTERM', () => childProcessor.waitForCurrentJobAndExit());
52+
process.on('SIGINT', () => childProcessor.waitForCurrentJobAndExit());
53+
54+
process.on('uncaughtException', async err => {
55+
if (typeof err !== 'object') {
56+
err = new Error(toString(err));
57+
}
58+
59+
await send({
60+
cmd: ParentCommand.Failed,
61+
value: errorToJSON(err),
62+
});
63+
64+
process.exit();
65+
});
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/**
2+
* A simple processor for testing non-BullMQ message handling.
3+
*/
4+
'use strict';
5+
6+
module.exports = function(job) {
7+
return Promise.resolve({ processed: true, data: job.data });
8+
};

tests/sandboxed_process.test.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,24 @@ describe('Sandboxed process using child processes', () => {
5757
await connection.quit();
5858
});
5959

60+
it('should handle non-BullMQ messages during child initialization', async function () {
61+
const mainFile = __dirname + '/fixtures/fixture_main_non_bullmq_messages.js';
62+
const processFile = __dirname + '/fixtures/fixture_processor_simple.js';
63+
64+
const child = new Child(mainFile, processFile, {
65+
useWorkerThreads: false,
66+
});
67+
68+
// This should complete successfully even though non-BullMQ messages
69+
// are sent before the InitCompleted message
70+
await child.init();
71+
72+
expect(child.exitCode).to.be.null;
73+
expect(child.killed).to.be.false;
74+
75+
await child.kill();
76+
});
77+
6078
it('should allow to pass workerForkOptions', async () => {
6179
const processFile = __dirname + '/fixtures/fixture_processor.js';
6280

0 commit comments

Comments
 (0)