Running Node app through Grunt - node.js

I am trying to run my Node application as a Grunt task. I need to spawn this as a child process, however, to allow me to run the watch task in parallel.
This works:
grunt.registerTask('start', function () {
grunt.util.spawn(
{ cmd: 'node'
, args: ['app.js']
})
grunt.task.run('watch:app')
})
However, when changes are detected by the watch task, this will trigger the start task again. Before I spawn another child process of my Node app, I need to kill the previous one.
I can't figure out how to kill the process, however. Something like this does not work:
var child
grunt.registerTask('start', function () {
if (child) child.kill()
child = grunt.util.spawn(
{ cmd: 'node'
, args: ['app.js']
})
grunt.task.run('watch:app')
})
It appears that:
Even though I store the spawned process in a variable outside of the function context, it does not persist, so the next time the start task is run, child is undefined.
child has no kill function…

Take a look at grunt-nodemon which handles a lot of the headaches related to spawning a child process.

This is because grunt-contrib-watch currently spawns all task runs as child processes. So the variable child is not within the same process context. Fairly soon, grunt-contrib-watch#0.3.0 will be released with a nospawn option. This will let you configure the watch to spawn task runs within the same context and would make your above example work.
Take a look at this issue for a little more information:
https://github.com/gruntjs/grunt-contrib-watch/issues/45

Related

Executing bash scripts using child_process under PM2 causes the process to restart once the script completes

I built a home-grown Netlify. It answers webhooks from Github and executes a bash script to deploy a cute React SPA.
It works great but when run under a PM2 process manager environment, it restarts once the child process closes/exits. I've tested many things - I've even built a test endpoint that feeds it fake data as repeatedly committing fake deploys got tiresome.
Here's some basic code:
const childProcess = require('child_process');
async function processDeploy(deploy) {
console.log(`Processing commit: ${deploy.commit.id}...`);
childProcess.execFile('./deploy.sh', function (error, stdout, stderr) {
if (!error) {
// a function to report the result of the commit
postDeploy(stdout, stderr, deploy.commit, { state: 'deployed' });
} else {
postDeploy('{}', error, deploy.commit, { state: 'error' });
}
});
}
There's a bunch of supporting functions that keep track of the queue and so on to serve a basic status frontend.
I've spent a long time picking through Node and PM2 logs only to find... Nothing. And I think it's partly due to my suspicion that there isn't actually an error - PM2 executes the script, the script exits once completed, and PM2 decides that it's time to kill the process.
The process then restarts as it's set to restart on kill/die.
So, how does PM2 differ to npm start when running my Express-based app? More importantly, how do I fix it...
In case it's relevant, this is my ecosystem.config.js for PM2:
module.exports = {
apps: [
{
name: 'App',
script: 'bin/www',
exec_mode: 'fork',
instances: 1,
autorestart: true,
watch: false,
ignore_watch: ['node_modules', '.log'],
max_memory_restart: '4G',
},
],
};
Update:
I've tried Node versions 10, 12, and 14.
I've switched away from child_process.execFile to child_process.spawn
I've investigated memory issues and scoured PM2's Github issues.
I am now confident that PM2 is catching the child process's event and confusing it with the parent process's.
Terminal output:
Deploy child process exited with code 0 and signal null // child process event listener for exit
Deploy child process closed with code 0 // child process event listener for close
Processing commit completed.
Queue empty.
Something is trying to kill me. // parent process event listener for SIGINT

How can I run new independent process from node.js process

Is there any way, how to run a new independent process from node.js process?
Example:
console.log('Starting new process')
// fork bash script.sh
process.exit()
Node.js process is dead and script.sh still running.
I don't know how to implement, which function should I use?

electron and node on windows, kill a spawned process

i'm starting a background process (on windows) from electron main, something like this:
app_exe = require("child_process").spawn(
"app.exe" ,
[ "--params", ... ],
{ stdio: "ignore" }
);
this works fine, i can see this from process explorer:
but i cannot kill the process when the electron is closed ( .on("closed") or on("window-all-closed") )
i tried child.kill([signal]), but also tree-kill or taskkill with no results: only the first process (6036 from the example) is killed, the second (5760) remains stale.
also exec taskkill /F /T /PID doesn't kill it.
the only way to kill is exec taskkill /F /IM app.exe /T, but in this way i cannot run two instances of the electron app.
i'm missing something obvious on process management on windows?
I was seeing a similar issue on Windows 7 machines. I believe newer OS' will automatically kill the child processes.
What I had to do was to just save off the PID of the spawned-process and send it a SIGTERM message to kill it when all the windows closed. Now, if there's a chance that the process died by other means before the Electron app shut down, the OS may have recycled the child process' PID, so for extra robustness, I used the find-process npm module to make sure that the PID that I held on to is associated with the correct process.
const proc = cp.spawn("app.exe");
app.on("window-all-closed", async () => {
const list = await require("find-process")("pid", proc.pid);
app.quit();
if (list[0] && list[0].name.toLowerCase() === "app.exe")
process.kill(proc.pid);
});
Now if your Electron app does not exit gracefully (and the above code isn't run), you'd have to rely on another technique.
If you control the child process that you're spawning, you can try to kick off a thread that listens to or pings the main process. If it doesn't see the main process, it can kill itself.
If you don't control the spawned-app, then I'm out of ideas, but the above code will handle most cases.
I had exactly the same issue, and no question / answer on the forums could resolve that problem. So after some research i've found a simple workaround and im sharing it :
// Workaround to close all processes / sub-processes after closing the app
electron.app.once('window-all-closed', electron.app.quit);
electron.app.once('before-quit', () => {
window.removeAllListeners('close');
});
And its working perfectly for me, hope it does for you.
You can try it with this code:
ipcMain.on('exampletab:close', () => {
ipcMain.removeAllListeners();
exampleWindow.close();
});
This code save my lot of time. When you close your child window, then use removeAllListeners() to remove Previous closed Windows.

Format output of spawned gulp process like the parent process

Usecase: On large projects it can be nice to separate small projects into folders of their own with their own build process.
The following setup basically works on both windows and mac - I get the output of the child gulp process logged in the console - only problem is that it's not colored like the output of the parent process.
var spawnCmd = require('spawn-cmd');
gulp.task('default', function () {
// Run all the parent projects tasks first
// ....
// ....
// ....
// When done, cd to child directory
process.chdir('./some-dir-that-has-a-gulpfile');
// Run `gulp` in the child directory
var child = spawnCmd.spawn('gulp', ['default']);
// And pipe the output to the current process
child.stdout.pipe(process.stdout);
});
My question is how to display the output of the child gulp process in exactly the same way as the normal gulp process.
Edit: Duplicate of Is it possible for child processes in Node.js to preserve colored output?
You should inherit the stdio of the parent process. This correctly pipes the output to the same output, with colors and all.
Because you are using gulp, you should also add the --color always flag, in order for gulp to properly detect that you want colors.
var spawnCmd = require('spawn-cmd');
gulp.task('default', function () {
// When done, cd to child directory
process.chdir('./some-dir-that-has-a-gulpfile');
// Run `gulp` in the child directory
var child = spawnCmd.spawn('gulp', ['default', '--color', 'always'], {stdio: 'inherit'});
});

How to start a process in node.js that thinks its being run from the commandline

I'm running require('child_process').exec('npm install') as a child process in a node.js script, but I want it to retain console colors. I'm running in windows, but want this script to be portable (e.g. to linux). How do I start a process that think's it's being run from the console?
Note: I'd rather not have npm-specific answers, but an answer that allows me to trick any command.
You can do this by letting the child process inherit the master process' stdio streams. This means you need to user spawn rather than exec, and this what you'd do:
var spawn = require('child_process').spawn;
var child = spawn('npm', ['install'], {
stdio: 'inherit'
});

Resources