I'm trying to create a child process using spawn() with it's own terminal
parent.js:
const spawn = require('child_process').spawn;
console.log('started parent process...'); //this should be printed in the parent terminal
const child = spawn('start node', [`child.js`], {
cwd:__dirname,
shell: true,
stdio: [null, null, null, 'pipe']
});
const Name = 'general kenobi';
child.stdio[3].write(Name);
child.stdio[3].on('data', (data) => {
console.log('data=>', data.toString());
child.kill();
});
child.js:
console.log('started child process...');
(async()=>{
await new Promise(r=>setTimeout(r,3000));
try{
let net = require('net');
let pipe = new net.Socket({ fd: 3 });
pipe.on('data',(data)=>{
pipe.write(`hello there ${data}`);
});
}catch(err){console.log(err)}
await new Promise(r => setTimeout(r, 3000));
})();
the expected data should be data=> hello there general kenobi but it gives this error in the child terminal
throw new ERR_INVALID_FD_TYPE(type); ^ TypeError [ERR_INVALID_FD_TYPE]: Unsupported fd type: UNKNOWN at new NodeError (node:internal/errors:371:5) at createHandle (node:net:152:9) at new Socket (node:net:340:20) at Object.<anonymous> (C:\...\parent.js:4:12) at Module._compile (node:internal/modules/cjs/loader:1101:14) at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10) at Module.load (node:internal/modules/cjs/loader:981:32) at Function.Module._load (node:internal/modules/cjs/loader:822:12) at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12) at node:internal/main/run_main_module:17:47 { code: 'ERR_INVALID_FD_TYPE' }
I couldn't find many references so I used this video as a guide
(please try to avoid a 3rd party package while answering)
Remove shell: true and change command to 'node' in parent.js file.
const child = spawn('node', [`child.js`], {
cwd:__dirname,
stdio: [null, null, null, 'pipe']
});
Instead of using spawn itself, while adding shell: true, spawn will use shell of your system to run that command. generally, I suggest use pure spawn without using shell. The risk will reduce without touching shell directly and problem of piping data.
First, as others mentioned in the comments, 'start node' should be just 'node'.
I compared the video you linked and found out if you change 'node' (the spawn argument) to 'process.execPath' it magically works!
parent.js:
const spawn = require('child_process').spawn;
console.log('started parent process...'); //this should be printed in the parent terminal
const child = spawn(process.execPath, [`child.js`], {
//cwd:__dirname,
//shell: true,
stdio: [null, null, null, 'pipe']
});
const Name = 'general kenobi';
child.stdio[3].write(Name);
child.stdio[3].on('data', (data) => {
console.log('data=>', data.toString());
child.kill();
});
I'm not currently sure why this is happening?? It might just be a bug I guess! For now, I thought maybe only the fix helps you.
If you log the process.execPath and as It was mentioned in the docs, it returns the absolute path to node and resolves all symbolic links too. This might be the problem with spawn.
Also if you use shell: true in the options, the child process doesn't get killed. I don't know if it's expected behaviour for you or not.
Update:
The problem in my ubuntu was because of using node from snap packages, and it's probably a bug from snap trying to sandbox the process.
I have opened a topic in snapcraft and it's probably a known bug with snaps about file descriptor. You can read more about workarounds and the bug in the link.
Update 2:
Another method to achieve using spawning the message on second command line.
parent.js:
const spawn = require('child_process').spawn;
console.log('started parent process...');
const child = spawn('node', ['child.js'], {
cwd: __dirname,
stdio: [null, null, null, 'ipc'],
});
const Name = 'general kenobi';
child.send(Name);
child.on('message', (data) => {
console.log('data=>', data);
// child.kill();
});
child.js:
const spawn = require('child_process').spawn;
console.log('started child process...');
process.on('message', (data) => {
process.send(`hello there ${data}`);
const cmd = spawn('start', ['cmd.exe', '/k', `echo hello there ${data}`], {
cwd: __dirname,
shell: true,
});
});