How to release resources from processes killed by grunt-contrib-watch? - node.js

I'm trying to use the module grunt-contrib-watch to restart my node.js server whenever certain files change. I already use grunt to run the server, jshint, and the template compiler, and I know those functions work. Here's the task to start the server:
grunt.registerTask('runServer', 'Starts the server.', function(){
grunt.log.writeln('Starting server...');
var done = this.async();
var child = grunt.util.spawn({
cmd: process.argv[0],
args: ['server.js'],
}, function(){
grunt.log.writeln('Server stopped!');
done(true);
});
child.stdout.pipe(process.stdout);
child.stderr.pipe(process.stderr);
});
Here's the config for the watch task:
watch: {
all: {
files: ['some/files/*.js'],
tasks: ['default'],
options: {
spawn: true,
interrupt: true,
reload: true,
}
}
}
When the task is restarted, the server fails because of an "EADDRINUSE" exception, which I take to mean is because the previous child process didn't release the port it was using, which is strange - I do see the "Server stopped!" message. I have tried this with all combinations of the three options, and I looked on the github page for grunt-contrib-watch, and nothing showed anything. How can I make the interrupted node.js process close all its resources before the next one tries to start?

Is it necessary to perform a child process spawn? In every case that I have spun up a server, I have simply done something like this:
grunt.registerTask('runServer', 'Starts the server.', require('./server'));
The watch task remains the same as you have it listed. Grunt automatically kills the previous run of that task as long as it is not a child process. This seems to work just fine for me.
However, if you NEED to spawn a child process and then kill it:
var spawn = require('child_process').spawn,
server = undefined;
...
grunt.registerTask('runServer', 'Starts the server.', function(){
grunt.log.writeln('Starting server...');
if (server)
server.kill('SIGUSR2');
server = spawn('node', ['server.js'], {stdio: 'inherit'});
}
...
grunt.registerTask('default', ['runServer']);

Related

advantage of creating node server in background

Until today in all my node\express projects, I have created the HTTP server in some file
var server = http.createServer(app);
http.globalAgent.maxSockets = maxSockets;
server.listen(port, function() {
logger.info('App starting on : ' + port );
});
and called that file directly to start the app. Recently i am noticing some boilerplates, using the approach of calling a starter file and based on arguments, spawn a child process, be it building the app or starting the app
in package json
"start": "babel-node tools/run.js"
in run .js
// Launch `node build/server.js` on a background thread
function spawnServer() {
return cp.spawn(
'node',
[
// Pre-load application dependencies to improve "hot reload" restart time
...Object.keys(pkg.dependencies).reduce(
(requires, val) => requires.concat(['--require', val]),
[],
),
// If the parent Node.js process is running in debug (inspect) mode,
// launch a debugger for Express.js app on the next port
...process.execArgv.map(arg => {
if (arg.startsWith('--inspect')) {
const match = arg.match(/^--inspect=(\S+:|)(\d+)$/);
if (match) debugPort = Number(match[2]) + 1;
return `--inspect=${match ? match[1] : '0.0.0.0:'}${debugPort}`;
}
return arg;
}),
'--no-lazy',
// Enable "hot reload", it only works when debugger is off
...(isDebug
? ['./server.js']
: [
'--eval',
'process.stdin.on("data", data => { if (data.toString() === "load") require("./server.js"); });',
]),
],
{ cwd: './build', stdio: ['pipe', 'inherit', 'inherit'], timeout: 3000 },
);
}
eg : https://github.com/kriasoft/nodejs-api-starter/
how is this advantageous?
In my experience this is not a widespread practice. It appears based on the comments that they're doing it in order to be able to do configuration on command line options based on the environment and so on. To be honest, this seems a bit counterproductive to me.
What I've seen far more often is to start node from the command line with just npm start. package.json has several options for defining what that will do, but most often I would just have it call something simple like node server.js or similar. If you have multiple options for starting that you want to offer (for example, turning on the debug flags and such), then just add more scripts and call npm run <scriptname> to make it happen.
Any other special sauce would be baked into the process manager of choice (systemd is my preference but others like pm2 exist and work well), and between that and the environment variables you can do all or most of what's in the above script without all the indirection. I feel like the example you posted would really up the 'wtf-factor' if I were starting to maintain the app and didn't know that at it was doing things like that for me under the hood.

How to setup gulp-watch with gulp-connect livereload?

Most questions and answers on this site do not contain an easy-to follow general approach to using these two libraries together.
So, being that we use the gulp-connect npm package, and we want to make use of the gulp-watch npm package, how do we set it up so that we can:
watch changes in some files
perform some operation, like building / compiling those files
live-reload the server once the building is done
First, you will define your build task. This can have pre-required tasks, can be a task of some sort, it doesn't matter.
gulp.task('build', ['your', 'tasks', 'here']);
Then, you will need to activate the connect server. It is important that you are serving the result of the compilation (in this example, the dist directory) and you're enabling livereload with the livereload: true parameter.
const connect = require('gulp-connect');
gulp.task('server', function() {
return connect.server({
root: 'dist',
livereload: true
});
});
Finally, you will setup your watch logic. Note that we're using watch and not gulp.watch. If you decide to change it, notice that their APIs are different and they have different capabilities. This example uses gulp-watch.
const watch = require('gulp-watch');
gulp.task('watch-and-reload', ['build'], function() {
watch(['src/**'], function() {
gulp.start('build');
}).pipe(connect.reload());
});
gulp.task('watch', ['build', 'watch-and-reload', 'server']);
The watch-and-reload task will depend on the build task, so that it ensures to run at least one build.
Then, it will watch for your source files, and in the callback, it will start the build task. This callback gets executed every time that a file is changed in the directory. You could pass an options object to the watch method to be more specific. Check the usage API in their repository.
Also, you will need to start the build action, for which we're using gulp.start. This is not the recommended approach, and will be deprecated eventually, but so far it works. Most questions with these issues in StackOverflow will look for an alternative workaround that changes the approach. (See related questions.)
Notice that gulp.start is called synchronously. This is what you want, since you want to allow the build task to finish before you proceed with the event stream.
And finally, you can use the event stream to reload the page. The event stream will correctly capture what files changed and will reload those.
Bringing up to speed, as per current stable gulp release
gulp.task API isn't the recommended pattern anymore. Use exports object to make public tasks
From official documentation: https://gulpjs.com/docs/en/api/task#task
To Configure watch and livereload you need following
gulp.watch
gulp-connect
watch function is available in gulp module itself
install gulp-connect using npm install --save-dev gulp-connect
To configure gulp-connect server for livereload we need to set property livereload to true
Run all tasks followed by task that calls watch function in which globs and task are given. Any changes to files that match globs trigger task passed to watch().
task passed to watch() should signal async complection else task will not be run a second time. Simple works: should call callback or return stream or promise
Once watch() is configured, append .pipe(connect.reload()) followed by pipe(dest(..)) where ever you think created files by dest are required to reload
Here is simple working gulpfile.js with connect lifereload
const {src, dest, watch, series, parallel } = require("gulp");
const htmlmin = require("gulp-htmlmin");
const gulpif = require("gulp-if");
const rename = require('gulp-rename');
const connect = require("gulp-connect");
//environment variable NODE_ENV --> set NODE_ENV=production for prouduction to minify html and perform anything related to prod
mode = process.env.NODE_ENV || 'dev';
var outDir = (mode != 'dev') ? 'dist/prod': 'dist/';
const htmlSources = ['src/*.html'];
function html() {
return src(htmlSources)
.pipe(gulpif(
mode.toLowerCase() != 'dev',
htmlmin({
removeComments: true,
collapseWhitespace: true,
minifyCSS: true,
minifyJS: true
})
)
)
.pipe(dest(outDir))
.pipe(connect.reload());
}
function js(){
return src('src/*.js')
.pipe(uglify())
.pipe(rename({ extname: '.min.js' }))
.pipe(dest(outDir))
.pipe(connect.reload());
}
function server() {
return connect.server({
port: 8000,
root: outDir,
livereload: true
})
}
function watchReload() {
let tasks = series(html, js);
watch(["src/**"], tasks);
}
exports.html = html;
exports.js = js;
exports.dev = parallel(html, js, server, watchReload);
Configure connect server with livereload property
function server() {
return connect.server({
port: 8000,
root: outDir,
livereload: true //essential for live reload
})
}
Notice .pipe(connect.reload()) in the above code. It is essential that stream of required files to be piped to connect.reload() else it may not work if you call connect.reload() arbitrarily
function html() {
return src(htmlSources)
.pipe(gulpif(
mode.toLowerCase() != 'dev',
htmlmin({
removeComments: true,
collapseWhitespace: true,
minifyCSS: true,
minifyJS: true
})
)
)
.pipe(dest(outDir))
.pipe(connect.reload()); //Keep it if you want livereload else discard
}
Since we configure public task dev following command will execute all tasks followed by connect and watchReload
gulp dev

Gulp: Run multiple node scripts in parallel

I've got two server scripts (both are relying on socket.io; running on different ports).
I'd like to start both in parallel via gulp. But in addition I'd like to have a possibility to stop one of them. And maybe even access the console output of each script.
Is there any existing solution for this? Or would you even recommend using anything else than gulp?
I found a solution in which I additionally start a mongoDB server:
var child_process = require('child_process');
var nodemon = require('gulp-nodemon');
var processes = {server1: null, server2: null, mongo: null};
gulp.task('start:server', function (cb) {
// The magic happens here ...
processes.server1 = nodemon({
script: "server1.js",
ext: "js"
});
// ... and here
processes.server2 = nodemon({
script: "server2.js",
ext: "js"
});
cb(); // For parallel execution accept a callback.
// For further info see "Async task support" section here:
// https://github.com/gulpjs/gulp/blob/master/docs/API.md
});
gulp.task('start:mongo', function (cb) {
processes.mongo = child_process.exec('mongod', function (err, stdout, stderr) {});
cb();
});
process.on('exit', function () {
// In case the gulp process is closed (e.g. by pressing [CTRL + C]) stop both processes
processes.server1.kill();
processes.server2.kill();
processes.mongo.kill();
});
gulp.task('run', ['start:mongo', 'start:server']);
gulp.task('default', ['run']);
nodemon/foreverjs is a good solution for not complicated cases, but they are not as scalable as pm2 is. So, if you want a scalable and reliable solution I'd recommend to use pm2.
Also, it worth mentioning that pm2 daemonizes after start unlike foreverjs/nodemon. It could be a bug or a feature for you and generally depends on your needs.
pm2 start script1.js
pm2 start script2.js
pm2 status // show status of running processes
pm2 logs // tail -f logs from running processes

Using grunt to run a node server and do cleanup after

So basically this is what I want to do. Have a grunt script that compiles my coffee files to JS. Then run the node server and then, either after the server closes or while it's still running, delete the JS files that were the result of the compilation and only keep the .coffee ones.
I'm having a couple of issues getting it to work. Most importantly, the way I'm currently doing it is this:
grunt.loadNpmTasks("grunt-contrib-coffee");
grunt.registerTask("node", "Starting node server", function () {
var done = this.async();
console.log("test");
var sp = grunt.util.spawn({
cmd: "node",
args: ["index"]
}, function (err, res, code) {
console.log(err, res, code);
done();
});
});
grunt.registerTask("default", ["coffee", "node"]);
The problem here is that the node serer isn't run in the same process as grunt. This matters because I can't just CTRL-C once to terminate JUST the node server.
Ideally, I'd like to have it run in the same process and have the grunt script pause while it's waiting for me to CTRL-C the server. Then, after it's finished, I want grunt to remove the said files.
How can I achieve this?
Edit: Note that the snippet doesn't have the actual removal implemented since I can't get this to work.
If you keep the variable sp in a more global scope, you can define a task node:kill that simply checks whether sp === null (or similar), and if not, does sp.kill(). Then you can simply run the node:kill task after your testing task. You could additionally invoke a separate task that just deletes the generated JS files.
For something similar I used grunt-shell-spawn in conjunction with a shutdown listener.
In your grunt initConfig:
shell: {
runSuperCoolJavaServer:{
command:'java -jar mysupercoolserver.jar',
options: {
async:true //spawn it instead!
}
}
},
Then outside of initConfig, you can set up a listener for when the user ctrl+c's out of your grunt task:
grunt.registerTask("superCoolServerShutdownListener",function(step){
var name = this.name;
if (step === 'exit') process.exit();
else {
process.on("SIGINT",function(){
grunt.log.writeln("").writeln("Shutting down super cool server...");
grunt.task.run(["shell:runSuperCoolJavaServer:kill"]); //the key!
grunt.task.current.async()();
});
}
});
Finally, register the tasks
grunt.registerTask('serverWithKill', [
'runSuperCoolJavaServer',
'superCoolServerShutdownListener']
);

Nodemon-like task in Grunt : execute node process and watch

I feel like I'm missing something.
Here is what I want to achieve :
Having a grunt task that executes my server.js and runs watch task in parallel. It feels to me that this is precisely one of the tasks grunt was designed for but I can't achieve this configuration.
Among others, I have read this :
Running Node app through Grunt
but I still can't make it.
Here is my Gruntfile.js :
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
watch: {
scripts: {
files: ['*.js'],
tasks: ['start'],
options: {
nospawn: true
}
}
}
});
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.registerTask('start', function() {
grunt.util.spawn({
cmd: 'node',
args: ['server.js']
});
grunt.task.run('watch');
});
grunt.registerTask('default', 'start');
};
I have "grunt-contrib-watch": "~0.3.1" which should be higher version than grunt-contrib-watch#0.3.0 as in the previously mentioned post.
If you could help me achieve the proper configuration, I would be extremely grateful. But more in general, I don't understand why there is no official grunt-contrib-nodemon-like package and task since I have the feeling it would be another great reason to use grunt (which I really like as a tool !)
Thanks
Edit: grunt-nodemon
since writing this, a nice person developed that.
I was having a lot of trouble using grunt.util.spawn to fire off new processes. They would run, but they wouldn't give me any output back. Perhaps you can figure out what I could not in these docs. http://gruntjs.com/api/grunt.util#grunt.util.spawn
Two problems I see with what you have:
I think grunt.registerTask() has to take three arguments when you use a callback function to run your task.
I don't think you can just call node server.js over and over again everytime a file changes. It will work on the first time, for it to really work you'd have to manage the server as a child process, killing and restarting it on subsequent file changes.
For the registerTask arguments try this, just to see if you can get something to work in your current implementation.
http://gruntjs.com/api/grunt.task#grunt.task.registertask
It takes (taskName, description, taskFunction) like so:
grunt.registerTask('start', 'My start task description', function() {
grunt.util.spawn({
cmd: 'node',
args: ['server.js']
});
grunt.task.run('watch');
});
That might at least get your watch to run node server.js the first time a file changes.
Here's what I would do instead.
Either just use nodemon $ nodemon server.js as is
or...
Read the source and use grunt-develop
He is managing the server as a child process, might be what you're looking for.
or...
Get grunt-shell
npm install grunt-shell --save-dev
And use it to run nodemon for you:
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
serverFile: 'server.js',
shell: {
nodemon: {
command: 'nodemon <%= serverFile %>',
options: {
stdout: true,
stderr: true
}
}
},
watch: { /* nothing to do in watch anymore */ }
});
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-shell');
grunt.registerTask('default', 'shell:nodemon');
};
$ grunt shell:nodemon
I sincerely hope that helps. Good luck!
Hi I also came across this problem and here is my solution (based on nackjicholson's answer). This uses grunt-nodemon in a spawned process. so I can:
Reload nodejs
Watch for changes to e.g. .less files
Get output of both tasks
grunt.loadNpmTasks('grunt-nodemon');
grunt.initConfig({
nodemon: {
dev: {
options: {
file: 'server.js',
nodeArgs: ['--debug'],
env: {
PORT: '8282'
}
}
}
},
});
grunt.registerTask('server', function (target) {
// Running nodejs in a different process and displaying output on the main console
var nodemon = grunt.util.spawn({
cmd: 'grunt',
grunt: true,
args: 'nodemon'
});
nodemon.stdout.pipe(process.stdout);
nodemon.stderr.pipe(process.stderr);
// here you can run other tasks e.g.
// grunt.task.run([ 'watch' ]);
});
Use grunt-concurrent
The issue is that tasks like watch and nodemon will never terminate, so grunt will never reach them. You need to spawn a new process.
You can do this easily using grunt-concurrent:
https://github.com/sindresorhus/grunt-concurrent
For example:
module.exports = function(grunt) {
grunt.initConfig({
...
concurrent: {
dev: {
tasks: ['nodemon', 'watch'],
options: {
logConcurrentOutput: true
}
}
}
});
};
The two will now run happily side by side.

Resources