Gulp: Run multiple node scripts in parallel - node.js

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

Related

gulp / gulp-nodemon - Nodemon never starts

I am trying to set up a serve task that will do the following:
Call a watch task to watch for any source changes. ( the watch task calls a build task that builds the app into a "build" folder )
Start the app using Nodemon ( gulp-nodemon )
If a source change happens - rebuild the app and restart nodemon
So far I've written the following tasks:
gulp.task('build', gulp.series(['lint'], () => {
del.sync(['./build/**/*.*']);
const tsCompile = gulp.src('./src/**/*.ts')
.pipe(gulpSourcemaps.init())
.pipe(project());
return tsCompile.js.pipe(gulpSourcemaps.write({
sourceRoot: file => path.relative(path.join(file.cwd, file.path), file.base)
}))
.pipe(gulp.dest('./build/'));
}));
gulp.task('watch', gulp.series(['build'], () => {
gulp.watch('./src/**/*.ts', gulp.series(['build']));
}));
gulp.task('serve', gulp.series(['watch'], () => {
return gulpNodemon({
script: './build/index.js',
watch: './build/'
});
}));
The current behavior of the tasks is:
I start the application by typing gulp serve
The watch tasks is called and it works as expected
Nodemon does not start and the process is stuck at the watch task. If I change any of the source code, the watch task will be called.
Basically, Nodemon does not start and only the watch task is working.
I am not able to figure out why the following behavior happens and I want to ask if anyone knows what the problem could be?
Use are running your watch task in series.
However, the watch task does not end so nodemon never starts.
Try using gulp.parallel() instead of gulp.series():
gulp.task('serve', gulp.parallel('watch', () => {
return gulpNodemon({
script: './build/index.js',
watch: './build/'
});
}));
Hopefully this should solve your problem.

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 release resources from processes killed by grunt-contrib-watch?

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']);

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']
);

Automate Jasmine-Node and express.js

I created a simple Webapp using express.js and want to test it with jasmine-node. Works fine so far but my problem is that I have to start the server manually every time before I can run my tests.
Could you help me on how to write a spec-helper that runs the server (with another port then my development one) just for the tests and then kills it afterwards?
This is what I do:
I have a server.js file inside the root of my node project that sets up the node application server (with express) and exports 2 methods:
exports.start = function( config, readyCallback ) {
if(!this.server) {
this.server = app.listen( config.port, function() {
console.log('Server running on port %d in %s mode', config.port, app.settings.env);
// callback to call when the server is ready
if(readyCallback) {
readyCallback();
}
});
}
};
exports.close = function() {
this.server.close();
};
The app.js file will be simple at this point:
var server = require('./server');
server.start( { port: 8000 } );
So the files/folder basic structure would be the following:
src
app.js
server.js
Having this separation will allow you to run the server normally:
node src/app.js
..and/or require it from a custom node script, which could be a node script (or a jake/grunt/whatever task) that executes your tests like this:
/** my-test-task.js */
// util that spawns a child process
var spawn = require('child_process').spawn;
// reference to our node application server
var server = require('./path/to/server.js');
// starts the server
server.start( { port: 8000 }, function() {
// on server ready launch the jasmine-node process with your test file
var jasmineNode = spawn('jasmine-node', [ '.path/to/test/file.js' ]);
// logs process stdout/stderr to the console
function logToConsole(data) {
console.log(String(data));
}
jasmineNode.stdout.on('data', logToConsole);
jasmineNode.stderr.on('data', logToConsole);
jasmineNode.on('exit', function(exitCode) {
// when jasmine-node is done, shuts down the application server
server.close();
}
});
I use Mocha - which is damn similar - but the same principle should apply: you could try requireing your app.js file in a 'beforeEach' hook inside the main describe. That should fire it up for you.
Assuming you use some code that invokes app.listen() in server.js, don't require the file on each run but only once and then have two functions like
startServer = -> app.listen(3000)
stopServer = -> app.close()
Then you can use these in beforeEach and afterEach
If you want then to go one step further in automating your testing while you develop, you can go to your terminal line and execute
jasmine-node . --autotest
Jasmine then will stay listening to every file inside your project and whenever you make changes to one it will tell if that piece of your code breaks any of your tests ;)

Resources