Я работаю над приложением koa с командой разработчиков, использующих код Visual Studio. В последние две недели мы видели эту ошибку, когда отправляли сообщение в Node.js дочерний процесс
Error [ERR_IPC_CHANNEL_CLOSED]: Channel closed
at ChildProcess.target.send (internal/child_process.js:678:16)
Мы запускаем приложение в нашем пакете json примерно так :
"nodemon --exec 'node --inspect=7003 index.js'"
Когда я удаляю оператор --inspect=7003
, дочерний процесс работает должным образом. Когда я запускаю его с инспектором, я получаю эти ошибки вместе с дочерним процессом, закрывающим канал, как только сообщение отправляется
Starting inspector on 127.0.0.1:7003 failed: address already in use
Я получаю эти ошибки независимо от того, какой порт I попробуйте запустить инспектора.
У меня есть коллега, который запускает код в Windows ОС, тогда как я использую MacOS и не получаю ни одной из ошибок, мы оба запускаем код с node -v 12.6.0
и vscode 1.43.1
. У нас есть другой коллега, у которого ошибка канала закрыта, независимо от того, работает ли он инспектором или нет.
У нас также есть приложение, работающее в облаке, и мы периодически получаем ту же ошибку, даже если у нас не работает инспектор.
Я проверил, и нормальное поведение приложения успешно закрывает дочерние процессы, и у меня нет возможности проверить, не нарушают ли некоторые из них некоторые дочерние процессы, открытые и потерянные.
Я создал простое приложение, в котором я могу повторить проблему локально, вот код:
Индекс. js
const Koa = require('koa');
const bodyParser = require('koa-bodyparser');
const helmet = require('koa-helmet');
const routes = require('./routes');
const PORT = 3088;
const app = new Koa();
app.use(helmet());
app.use(bodyParser());
app.use((ctx, next) => {
const key = ctx.get('health');
if (key) {
return (ctx.response.status = 200);
}
return next();
});
routes(app);
app.listen(PORT, () => {
console.log(`App running on port: ${PORT}`);
});
маршруты. js
const { processThing } = require('./parent.js');
const Router = require('koa-router');
const router = new Router();
router.get('/process', processThing);
module.exports = app => {
app.use(router.routes());
};
parent. js
const { fork } = require('child_process');
const forked = fork(`${__dirname}/child-process.js`);
const processThing = async ({ request, response }) => {
console.log('doing processing')
// we do something asynchronous in our actual code base
const TIMEOUT = 1800000;
forked.on('message', async ({ status, error }) => {
timeoutId && clearTimeout(timeoutId);
forked.kill();
console.log('status', status)
return status;
})
forked.on('error', async error => {
console.log(error, 'error')
timeoutId && clearTimeout(timeoutId);
forked.kill();
});
console.log('sending hello')
forked.send('hello');
timeoutId = setTimeout(async () => {
forked.kill();
console.log('timed out')}, TIMEOUT);
// send message to say that child process has started processing
response.status = 204;
return response;
};
module.exports = { processThing };
child-process. js
process.on('message', async string => {
console.log('did thing');
process.send({
status: 'DONE'
});
});
package. json
{
"name": "test-child-process",
"version": "1.0.0",
"description": "",
"main": "child-process.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "nodemon --exec 'node --inspect=7003 index.js'"
},
"author": "",
"license": "ISC",
"dependencies": {
"koa": "^2.11.0",
"koa-bodyparser": "^4.2.1",
"koa-helmet": "^5.2.0",
"koa-router": "^8.0.8",
"nodemon": "^2.0.2"
}
}
Может кто-нибудь сказать мне, почему мы с коллегами закрыли этот канал по ошибке? Если это из-за потерянных дочерних процессов, есть ли у кого-нибудь предложения о том, как я могу их найти и убить?
---------------------- ПРАВКА ---------------------------------
С некоторой помощью мы поняли, что проблема была раздвоена вызов должен быть внутри метода, в противном случае при первоначальной сборке приложения создается только один дочерний процесс, и в конце концов он блокируется по тайм-ауту и закрывается. Генерируя дочерний процесс внутри родительского метода, а также перезаписывая унаследованные аргументы (инспектор), он работает каждый раз:
Обновленный родительский. js
const { fork } = require('child_process');
const processThing = async ({ request, response }) => {
console.log('doing processing')
//this is now inside the function
const forked = fork(`${__dirname}/child-process.js`, {
execArgv: ['--max-old-space-size=6144']
});
// we do something asynchronous in our actual code base
const TIMEOUT = 1800000;
forked.on('message', async ({ status, error }) => {
timeoutId && clearTimeout(timeoutId);
forked.kill();
console.log('status', status)
return status;
})
forked.on('error', async error => {
console.log(error, 'error')
timeoutId && clearTimeout(timeoutId);
forked.kill();
});
console.log('sending hello')
forked.send('hello');
timeoutId = setTimeout(async () => {
forked.kill();
console.log('timed out')}, TIMEOUT);
// send message to say that child process has started processing
response.status = 204;
return response;
};
module.exports = { processThing };
Однако, когда я не перезаписывайте унаследованный аргумент инспектора, теперь он все еще не запускает дочерний процесс, но теперь не возвращает дочерние журналы консоли, он просто выходит из системы, что адрес уже используется. Я предполагаю, что инспектор, который не запускается, приводит к сбою дочернего процесса, и нам нужно посмотреть на совместное использование порта с ребенком, изменив запуск. json но если у кого-то есть какие-либо другие мысли или объяснения, я бы хотел их услышать.