How to debug Node.JS child forked process? - node.js

I'm trying to debug the child Node.JS process created using:
var child = require('child_process');
child .fork(__dirname + '/task.js');
The problem is that when running in IntelliJ/WebStorm both parent and child process start on the same port.
debugger listening on port 40893
debugger listening on port 40893
So it only debugs the parent process.
Is there any way to set IntelliJ to debug the child process or force it to start on a different port so I can connect it in Remote debug?

Yes. You have to spawn your process in a new port. There is a workaround to debug with clusters, in the same way you can do:
Start your app with the --debug command and then:
var child = require('child_process');
var debug = typeof v8debug === 'object';
if (debug) {
//Set an unused port number.
process.execArgv.push('--debug=' + (40894));
}
child.fork(__dirname + '/task.js');
debugger listening on port 40894

It is a known bug in node.js that has been recently fixed (although not backported to v0.10).
See this issue for more details: https://github.com/joyent/node/issues/5318
There is a workaround where you alter the command-line for each worker process, although the API was not meant to be used this way (the workaround might stop working in the future). Here is the source code from the github issue:
var cluster = require('cluster');
var http = require('http');
if (cluster.isMaster) {
var debug = process.execArgv.indexOf('--debug') !== -1;
cluster.setupMaster({
execArgv: process.execArgv.filter(function(s) { return s !== '--debug' })
});
for (var i = 0; i < 2; ++i) {
if (debug) cluster.settings.execArgv.push('--debug=' + (5859 + i));
cluster.fork();
if (debug) cluster.settings.execArgv.pop();
}
}
else {
var server = http.createServer(function(req, res) {
res.end('OK');
});
server.listen(8000);
}

Quick simple fix ( where using chrome://inspect/#devices )
var child = require('child_process');
child.fork(__dirname + '/task.js',[],{execArgv:['--inspect-brk']});
Then run your app without any --inspect-brk and the main process won't debug but the forked process will and no conflicts.
To stop a fork conflicting when debugging the main process ;
child.fork(__dirname + '/task.js',[],{execArgv:['--inspect=xxxx']});
where xxxx is some port not being used for debugging the main process. Though I haven't managed to easily connect to both at the same time in the debugger even though it reports as listening.

I find that setting the 'execArgv' attribute in the fork func will work:
const child = fork('start.js', [], {
cwd: startPath,
silent: true,
execArgv: ['--inspect=10245'] });

if "process.execArgv" doenst work you have to try:
if (debug) {
process.argv.push('--debug=' + (40894));
}
this worked for me..

There are one more modern way to debug child (or any) process with Chrome DevTools.
Start your app with arg
--inspect
like below:
node --debug=9200 --inspect app/main.js
You will see the message with URL for each child process:
Debugger listening on port 9200.
Warning: This is an experimental feature and could change at any time.
To start debugging, open the following URL in Chrome:
chrome-devtools://devtools/bundled/inspector.html?experiments=true&v8only=true&ws=127.0.0.1:9200/207f2ab6-5700-4fc5-b6d3-c49a4b34a311
Debugger listening on port 9201.
Warning: This is an experimental feature and could change at any time.
To start debugging, open the following URL in Chrome:
chrome-devtools://devtools/bundled/inspector.html?experiments=true&v8only=true&ws=127.0.0.1:9201/97be3351-2ea1-4541-b744-e720188bacfa
Debugger listening on port 9202.
Warning: This is an experimental feature and could change at any time.
To start debugging, open the following URL in Chrome:
chrome-devtools://devtools/bundled/inspector.html?experiments=true&v8only=true&ws=127.0.0.1:9202/8eb8384a-7167-40e9-911a-5a8b902bb8c9
If you want to debug the remote processes, just change the address 127.0.0.1 to your own.

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

debugging protactor (with / without webstorm)

So I'm starting out with protractor, and I want to debug my test code:
describe('stuff', function(){
it('should find the specs item, and its empty', function(){
browser.debugger();
gotoHome();
var allItems = element.all('li in model.tags');
var specsDashboardElement;
for (var i=0 ; i < allItems.length; ++i) {
var elem = allItems[i];
var text = elem.findElement(by.css('.li-title').getText()); // does this even work?? dunno
if (text == "Specs")
specsDashboardElement = elem;
}
expect(specsDashboardElement.isDisplayed()).toBe(true);
});
});
I've followed these instructions, but this is the output I see on the node.js debugger console:
D:\src\apps\j1-test.module>protractor debug conf.js
< debugger listening on port 5858
connecting... ok
break in C:\Users\j\AppData\Roaming\npm\node_modules\protractor\lib\cli.js:7
5 * Values from command line options override values from the config.
6 */
7 'use strict';
8
9 // Coffee is required here to enable config files written in coffee-script.
debug> cont
< ------------------------------------
< PID: 9756 (capability: chrome #1)
< ------------------------------------
< debugger listening on port 5858
debug>
and that's it. no matter how many types I type 'cont', nothing happens.
I've tried following the instructions for debugging in WebStorm, with much the same result (output on the WebStorm debug console:
"C:\Program Files\nodejs\node.exe" --debug-brk=2259 C:\Users\j\AppData\Roaming\npm\node_modules\protractor\lib\cli.js
conf.js
debugger listening on port 2259
PID: 2708 (capability: chrome #1)
debugger listening on port 2259
).
I'm using node 0.10.26 (64 bit) on windows 8
Ideas anyone?
That was a Protractor issue, which should be fixed now:
"Fix is in - should be out next release. Thanks for your patience, everyone." - #juliemr
from GitHub issue #552
EDIT: Released in 0.20.0 version! (0.20.1 for Windows users). See Protractor changelog.

How to fork a child process that listens on a different debug port than the parent

I am trying to use child_process.fork to spawn a process that breaks and listens on the V8 debug protocol.
However, I can't get the forked process to listen on a port that's different from the parent process. Assuming the parent process listens on 6000, the child process also attempts to listen on port 6000:
Failed to open socket on port 6000, waiting 1000 ms before retrying
Here's my code:
// `test.js`, invoked as `node --debug-brk=6000 test.js`
var nodeModule, args, env, child
nodeModule = path.normalize(path.join(__dirname, '..', 'app.js'))
args = [
'--debug-brk=6001'
, '127.0.0.1'
, 3030
, 'api-testing'
]
env = { 'DB_URI': 'mongodb://localhost/test' }
child = require('child_process')
.fork(nodeModule, args, {env: env})
.on('message', callback)
As you can see, I'm trying to get the forked process to listen on port 6001, but the child process attempts to listen on port 6000 which is in use by the parent.
How can I get the child process to listen on port 6001, or some other free port?
There are several threads on this subject. For example:
How to debug Node.JS child forked process?
Debugging Node.js processes with cluster.fork()
However:
These threads deal with the cluster variant of forking
Refer to execArgv, which appear to have been undocumented for process and are still undocumented for cluster.
Simple enough answer, found on this comment and with some help from #Node.js on Freenode:
Just move the --debug-brk into the execArgv key of the options param to fork:
// Excerpt:
args = [
'127.0.0.1'
, 3030
, 'api-testing'
]
env = { 'DB_URI': 'mongodb://localhost/test' }
child = fork(nodeModule, args, {
env: env
, execArgv: ['--debug-brk=6001']
})
.on('message', this.callback)
execArgv is the array of parameters passed to the node process. argv is the set passed to the main module. There's a dedicated parameter to child_process.fork for argv, but execArgvs have to be placed within the opts param. This works, and in the child process we have:
> process.execArgv
["--debug-brk=6001"]
> process.argv
["/usr/local/Cellar/node/0.10.13/bin/node" "/Users/dmitry/dev/linksmotif/app.js", "127.0.0.1", "3030", "api-testing"]
In summary
Node.js consistently treats execArgv and argv as separate sets of values.
Before to fork remove old debug-brk parameter :
process.execArgv = process.execArgv.filter(function(o){
var x = "--debug-brk";
return o.substring(0, x.length) !== x
});
and add a new one:
process.execArgv.push("--debug-brk=9999");

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