Node.js child process with detached option - node.js

I am creating an electron desktop app, and I have code use spawn() with option detached: true. My purpose is to let the child process keep running even when the parent process terminated.
const spawn = require('child_process').spawn;
const ls = spawn('ls', ['-lh', '/usr'], { detached: true });
ls.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
fs.writeFileSync('path-to-test.txt', 'stdout');
});
ls.stderr.on('data', (data) => {
console.log(`stderr: ${data}`);
fs.writeFileSync('path-to-test.txt', 'stderr');
});
ls.on('close', (code) => {
console.log(`child process exited with code ${code}`);
});
squirrel events https://github.com/electron/grunt-electron-installer#handling-squirrel-events:
switch (squirrelCommand) {
case '--squirrel-install':
case '--squirrel-updated':
app.quit();
return true;
case '--squirrel-uninstall':
app.quit();
return true;
case '--squirrel-obsolete':
return true;
}
I tested the above code outside of squirrel events, it works well when the parent process is alive. But after I put these code inside squirrel events like --squirrel-uninstall (the parent process may terminated before/during child process run), it can only run commands, any code inside it (like fs function) doesn't work any more.
My have a question is: despite of squirrel event, can the logic code like fs inside child process work after the node parent process terminate?

Related

node: await with child process message handler

I'm having trouble wrapping my hands around some async/await code I'm working on. Is there a way to make a child process's message handler async? Here is what my child process file looks like:
// child.ts
import { writeImage } from './generate-images'
const slowFunction = async (imageAttributes) => {
console.log("inside child slowFunction....")
await writeImage(imageAttributes, 0, true)
}
process.on('message', (msg) => {
console.log('starting child....')
slowFunction(msg)
console.log('exiting child')
process.exit()
})
I am calling it via fork in a big loop in the parent process because i need to perform this slow function a few thousand times, this is a dumbed down version of what im calling inside a big loop in the parent:
// parent.ts
const child = child_process.fork(path.join(__dirname, 'child.ts'))
child.send(Array.from(imageAttributes)[i])
child.on('exit', function () {
console.log(`child exiting`)
// do some cleanup
})
the problem is that all my forks keep exiting before slowFunction finishes because its an async function, but i cant add async slowFunction(msg) because the process.on('message', ...) handler is not async.
any ideas?
You need to make process.on('message', ...) an async function. No callbacks will be async by default.
process.on('message', async (msg) => {
console.log('starting child....')
await slowFunction(msg)
console.log('exiting child')
process.exit()
})

setTimeout blocks Promise inside a child process

I encountered a weird issue with setTimeout inside a promise in a child process.
These are my files:
index.js:
const {spawnSync} = require('child_process');
const {resolve} = require('path');
const timeoutPromiseModule = resolve(__dirname, '.', 'timeout-promise');
const {stdout} = spawnSync('node', [timeoutPromiseModule]);
console.log(stdout.toString());
timeout-promise.js:
Promise.race([
Promise.resolve(),
new Promise((resolve, reject) => {
setTimeout(() => {reject('too long')}, 10000);
})
])
.then(x=> console.log('resolved'))
.catch(e => console.log('rejected'));
When I run node index.js I expected the output to be print immediatly but what actually happens is that the output hangs until setTimeout's callback is called by the child process.
What's causing this and how can this be resolved?
I'm guessing it's something to do with the child process's event loop that prevents the child process from closing until the messages empty?
I uploaded the code to GitHub for your convenience:
https://github.com/alexkubica/promise-race-settimeout-blocking-inside-child-process
The reason for this is that spawnSync will not return until the child process has fully closed as stated in the documentation:
The child_process.spawnSync() method is generally identical to
child_process.spawn() with the exception that the function will not
return until the child process has fully closed. [...]
Note that a node script will only exit when there are no more pending tasks in the eventloop's queue, which in this case happens after the timeout has resolved.
You can switch to spawn to see the immediatley resolved promise output:
const res = spawn('node', [timeoutPromiseModule]);
res.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
});
res.on('close', (code) => {
console.log(`child process exited with code ${code}`);
});

How to start a child process successfully in node without waiting for it to complete?

How do I ensure the child process has started without waiting for it to complete?
Here is my code.
const runMyProc = () => {
const cmd = "MyProc";
const MyProcProc = spawn(cmd);
if(!MyProcProc)
return false;
logger.info(`Started ${cmd} process with PID [${MyProcProc.pid}].`);
MyProcProc.on('error', (err) => {
logger.error(`Failed to run MyProc app ${err}`);
});
MyProcProc.on('close', (code) => {
logger.info(`child process close all stdio with code ${code}`)
});
MyProcProc.on('exit', (code) => {
logger.info(`Process exited with exit code ${code}`);
});
return true;
}

Why does my forked child process exit immediately after I fork it?

I'm just trying to fork a simple child process and have the IPC channel stay open but it keeps exiting immediately for some reason.
In parent.js:
var child = require('child_process').fork('./child.js');
child.on('hi', function() {
console.log("Hi");
});
child.on('exit', function() {
console.log("Exited");
});
child.send('hello');
In child.js:
process.on('hello', function() {
process.send('hi');
});
I get "Exited" printed to the console immediately, and never get a 'Hi'. Then if I continue to try to send to the child process I get a channel closed error.
Something I am doing wrong?
You need to keep both processes open as a child will close immediately and so will the parent. You can do so with something like this:
parent.js
var child = require('child_process').fork('./child.js');
child.on('message', function () {
console.log("Hi");
});
child.on('exit', function () {
console.log("Exited");
});
setTimeout(() => {
child.send('hello');
}, 1000);
process.stdin.resume();
child.js
process.on('message', function () {
console.log("sending hi");
process.send('hi');
});

How to pass parameter from node child process to execute commands in batch file?

I need to put all the commands in a batch file (test.cmd) with some logic, for example:
IF condition1 (c:\Windows\System32\schtasks.exe /Create ...)
Else (c:\Windows\System32\schtasks.exe /delete ...)
If remove the if-else statement, and only leave one command in test.cmd, by using code like this can execute the command:
exec('some-path/test.cmd', (error, stdout, stderr) => {
if (error) {
console.log(error);
return;
}
console.log(stdout);
});
If add if-else statement back, does anyone know how can I pass parameter from node.js exec() function? In the terminal, it is easy to pass parameters like "test.cmd para1".
Yo can use node spawn.
Example variables
const spawn = require('child_process').spawn;
const ls = spawn('ls', ['-lh', '/usr']);
ls.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
});
ls.stderr.on('data', (data) => {
console.log(`stderr: ${data}`);
});
ls.on('close', (code) => {
console.log(`child process exited with code ${code}`);
});
documentation:
https://nodejs.org/api/child_process.html

Resources