child_process: emit IPC messages on next tick
This commit fixes a regression related to IPC 'message' events. When messages are not emitted in the next tick, a 'message' handler that throws can break the IPC read loop. Refs: https://github.com/nodejs/node/pull/6909 Refs: https://github.com/nodejs/node/pull/13459 Refs: https://github.com/nodejs/node/pull/13648 PR-URL: https://github.com/nodejs/node/pull/13856 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Santiago Gimeno <santiago.gimeno@gmail.com>
This commit is contained in:
parent
748b2a87ca
commit
87d682b69a
@ -457,7 +457,6 @@ function setupChannel(target, channel) {
|
|||||||
}
|
}
|
||||||
chunks[0] = jsonBuffer + chunks[0];
|
chunks[0] = jsonBuffer + chunks[0];
|
||||||
|
|
||||||
var nextTick = false;
|
|
||||||
for (var i = 0; i < numCompleteChunks; i++) {
|
for (var i = 0; i < numCompleteChunks; i++) {
|
||||||
var message = JSON.parse(chunks[i]);
|
var message = JSON.parse(chunks[i]);
|
||||||
|
|
||||||
@ -466,12 +465,11 @@ function setupChannel(target, channel) {
|
|||||||
// that we deliver the handle with the right message however.
|
// that we deliver the handle with the right message however.
|
||||||
if (isInternal(message)) {
|
if (isInternal(message)) {
|
||||||
if (message.cmd === 'NODE_HANDLE')
|
if (message.cmd === 'NODE_HANDLE')
|
||||||
handleMessage(message, recvHandle, true, false);
|
handleMessage(message, recvHandle, true);
|
||||||
else
|
else
|
||||||
handleMessage(message, undefined, true, false);
|
handleMessage(message, undefined, true);
|
||||||
} else {
|
} else {
|
||||||
handleMessage(message, undefined, false, nextTick);
|
handleMessage(message, undefined, false);
|
||||||
nextTick = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jsonBuffer = incompleteChunk;
|
jsonBuffer = incompleteChunk;
|
||||||
@ -533,7 +531,7 @@ function setupChannel(target, channel) {
|
|||||||
|
|
||||||
// Convert handle object
|
// Convert handle object
|
||||||
obj.got.call(this, message, handle, function(handle) {
|
obj.got.call(this, message, handle, function(handle) {
|
||||||
handleMessage(message.msg, handle, isInternal(message.msg), false);
|
handleMessage(message.msg, handle, isInternal(message.msg));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -743,15 +741,13 @@ function setupChannel(target, channel) {
|
|||||||
target.emit(event, message, handle);
|
target.emit(event, message, handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleMessage(message, handle, internal, nextTick) {
|
function handleMessage(message, handle, internal) {
|
||||||
if (!target.channel)
|
if (!target.channel)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var eventName = (internal ? 'internalMessage' : 'message');
|
var eventName = (internal ? 'internalMessage' : 'message');
|
||||||
if (nextTick)
|
|
||||||
process.nextTick(emit, eventName, message, handle);
|
process.nextTick(emit, eventName, message, handle);
|
||||||
else
|
|
||||||
target.emit(eventName, message, handle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
channel.readStart();
|
channel.readStart();
|
||||||
|
39
test/parallel/test-child-process-ipc-next-tick.js
Normal file
39
test/parallel/test-child-process-ipc-next-tick.js
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
'use strict';
|
||||||
|
const common = require('../common');
|
||||||
|
const assert = require('assert');
|
||||||
|
const cp = require('child_process');
|
||||||
|
const NUM_MESSAGES = 10;
|
||||||
|
const values = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < NUM_MESSAGES; ++i) {
|
||||||
|
values[i] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.argv[2] === 'child') {
|
||||||
|
const received = values.map(() => { return false; });
|
||||||
|
|
||||||
|
process.on('uncaughtException', common.mustCall((err) => {
|
||||||
|
received[err] = true;
|
||||||
|
const done = received.every((element) => { return element === true; });
|
||||||
|
|
||||||
|
if (done)
|
||||||
|
process.disconnect();
|
||||||
|
}, NUM_MESSAGES));
|
||||||
|
|
||||||
|
process.on('message', (msg) => {
|
||||||
|
// If messages are handled synchronously, throwing should break the IPC
|
||||||
|
// message processing.
|
||||||
|
throw msg;
|
||||||
|
});
|
||||||
|
|
||||||
|
process.send('ready');
|
||||||
|
} else {
|
||||||
|
const child = cp.fork(__filename, ['child']);
|
||||||
|
|
||||||
|
child.on('message', common.mustCall((msg) => {
|
||||||
|
assert.strictEqual(msg, 'ready');
|
||||||
|
values.forEach((value) => {
|
||||||
|
child.send(value);
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user