It would be neat if you could chain process.on('exit') calls like so
process.on('exit', function firstHandler(err,code,cb){ //this signature is fictitious for this example only
if(condition){
cb(null); // this would call the next process.on('exit') listener
}
});
process.on('exit', function secondHandler(err,code,cb){
//we really exit this time
});
is this functionality possible somehow? I know this goes against the way event emitters / listeners work, but the reason I ask the question is because I want to prevent an exit if there is a certain condition and then reinvoke process.exit() once the condition is met.
It already works that way. By default, EventEmitters add event listeners when the on() method is called (default maximum is 10 listeners though you can change that). Since the exit event is implemente as a regular EventEmitter, you can add more than one listener by calling on() multiple times:
process.on('exit',function(){console.log('will exit')});
process.on('exit',function(){console.log('really, I will quit')});
process.on('exit',function(){console.log('DEAD')});
Output:
will exit
really, I will quit
DEAD
Note that the listeners will be called in the sequence they were added. See the documentation of Events for more info: https://nodejs.org/api/events.html
You can't cancel an exit. From the doc:
Emitted when the process is about to exit. There is no way to prevent the exiting of the event loop at this point, and once all 'exit' listeners have finished running the process will exit.
Once the "exit" event is emitted, you cannot prevent the node.js process from terminating.
However, if you listen for the "beforeExit" event, shown here:
https://nodejs.org/api/process.html
You can prevent the process / event loop from terminating by adding calls.
Related
I am new to node.js and working through the API. In the stream module docs I came across this example of the "unpipe event" (actually a fusion of two examples in the docs).
const fs = require("fs);
const writable = fs.createWriteStream("write.txt");
const readable = fs.createReadStream("read.txt");
readable.pipe(writable);
setTimeout(function(){
console.log("Stop writing to file.txt");
readable.unpipe(writable);
console.log("Manually close the file stream");
writable.end();
}, 0);
writable.on("unpipe", function(src){
console.log("Something has stopped piping into the writer");
});
I can't understand the following console.log order:
"Stop writing to file.txt"
"Something has stopped piping into the writer"
"Manually close the file stream"
Given the setTimeout callback is running - which is the first phase of the event loop as I understand - how on earth does the callback for the "unpipe" event start to run before the setTimeout callback has finished.
Originally I had the setTimeout firing after a time above zero seconds, however I was finding that the unpipe call back was always called first. I reasoned that my computer was reading the file always first before the setTimeout was ready. (Although I can't see any mention in the docs about the completion of the write to the file eliciting the "unpipe" event, but this makes sense I suppose). However I can't for the life of me reason how the above program flow is occurring. Thanks in advance for any help.
As specified by the node.js documentation:
The EventEmitter calls all listeners synchronously in the order in which they were registered.
That is, when .emit is called, it synchronously runs through all listeners for the emitted event and calls them.
Note that if necessary you can wrap your callback code in process.nextTick to ensure that it will always run asynchronously, but in your case it's likely that's unnecessary.
Also the source of the call to .emit (the emission of the event) will often be asynchronous.
I'm using node to wrap an executable and I'm using the spawn event emitter. See the docs here. There are multiple events to subsribe to.
child = spawn("path/to/exe", args)
child.on('close', exitNormally )
child.on('exit', exitNormally )
child.on('error', exitAbnormally )
child.on('disconnect', exitAbnormally )
Should I be subscribing to all of them or is subscribing to close and error enough? I have a callback that I have to execute regardless of whether the outcome is a success or not. The docs for the events are here but it doesn't seem to say explictly say what I'm asking and I want to confirm that my thinking is correct and I don't miss any exits.
The exit event always will be called if your process ends, so I think it will be enough.
I'm writing a NodeJS app that accepts command-line arguments. To parse the options, I'm using a Node package called Commander. There's one option (-f / --fileName) that I want to check. Here's what different inputs produce:
nodeapp --fileName sampleFile results in program.fileName="sampleFile"
nodeapp --fileName results in program.fileName=undefined
nodeapp" results results in program.fileName=undefined
I want nodeapp --fileName to throw a "Please specify a file name" error, but I want nodeapp to work fine.
Is there any standard that specifies how to deal with missing parameters, or a best-practice that I should follow?
In other words, if an option requires a parameter, and the parameter is not provided, should it be treated as an error case, or should the option be ignored?
I use commander occasionally. If it is a program-critical input I usually just check for it and exit the program with a message if it doesn't exist.
if(!argv.port) {
console.log('Please provide a port number.');
process.exit(0);
}
If it is not critical I usually pull it out into its own variable like:
var host = (argv.host) ? argv.host : '127.0.0.1';
This way it will default to my local machine if I don't pass it any host info.
The NodeJS documentation suggests that you either set exitCode to a non-zero value, or throw an uncaught error.
It specifically says that you should not use process.exit in the case where a condition is not met.
Here's the text of the documentation for process.exit:
Calling process.exit() will force the process to exit as quickly as
possible even if there are still asynchronous operations pending that
have not yet completed fully, including I/O operations to
process.stdout and process.stderr.
In most situations, it is not actually necessary to call
process.exit() explicitly. The Node.js process will exit on its own if
there is no additional work pending in the event loop. The
process.exitCode property can be set to tell the process which exit
code to use when the process exits gracefully.
For instance, the following example illustrates a misuse of the
process.exit() method that could lead to data printed to stdout being
truncated and lost:
// This is an example of what *not* to do:
if (someConditionNotMet()) {
printUsageToStdout();
process.exit(1);
}
The reason this is
problematic is because writes to process.stdout in Node.js are
sometimes asynchronous and may occur over multiple ticks of the
Node.js event loop. Calling process.exit(), however, forces the
process to exit before those additional writes to stdout can be
performed.
Rather than calling process.exit() directly, the code should set the
process.exitCode and allow the process to exit naturally by avoiding
scheduling any additional work for the event loop:
// How to properly set the exit code while letting the process exit gracefully.
if (someConditionNotMet()) {
printUsageToStdout();
process.exitCode = 1;
}
If it is necessary to terminate the Node.js
process due to an error condition, throwing an uncaught error and
allowing the process to terminate accordingly is safer than calling
process.exit().
I have the following node.js code:
var testProcess = spawn(item.testCommand, [], {
cwd: process.cwd(),
stdio: ['ignore', process.stdout, process.stderr]
});
testProcess.on('close', function(data) {
console.log('test');
});
waitpid(testProcess.pid);
testProcess.kill();
however the close method never gets calls.
The end result I am looking for is that I spwan a process and the the script waits for that child processs to finish (which waitpid() is doing correctly). I want the output/err of the child process to be display to the screen (which the stdio config is doing correctly). I also want to perform code on the close of the child process which I was going to do in the close event (also tried exit), but it does not fire.
Why is the event not not firing?
http://nodejs.org/api/process.html
Note that just because the name of this function is process.kill, it is really just a signal sender, like the kill system call. The signal sent may do something other than kill the target process.
You can specify the signal while Kill() call.
Looking at waitpid() I found out that it returns an object with the exitCode. I changed my code so that I just perform certain actions based on what the value of the exitCode is.
Consider:
node -e "setTimeout(function() {console.log('abc'); }, 2000);"
This will actually wait for the timeout to fire before the program exits.
I am basically wondering if this means that node is intended to wait for all timeouts to complete before quitting.
Here is my situation. My client has a node.js server he's gonna run from Windows with a Shortcut icon. If the node app encounters an exceptional condition, it will typically instantly exit, not leaving enough time to see in the console what the error was, and this is bad.
My approach is to wrap the entire program with a try catch, so now it looks like this: try { (function () { ... })(); } catch (e) { console.log("EXCEPTION CAUGHT:", e); }, but of course this will also cause the program to immediately exit.
So at this point I want to leave about 10 seconds for the user to take a peek or screenshot of the exception before it quits.
I figure I should just use blocking sleep() through the npm module, but I discovered in testing that setting a timeout also seems to work. (i.e. why bother with a module if something builtin works?) I guess the significance of this isn't big, but I'm just curious about whether it is specified somewhere that node will actually wait for all timeouts to complete before quitting, so that I can feel safe doing this.
In general, node will wait for all timeouts to fire before quitting normally. Calling process.exit() will exit before the timeouts.
The details are part of libuv, but the documentation makes a vague comment about it:
http://nodejs.org/api/all.html#all_ref
you can call ref() to explicitly request the timer hold the program open
Putting all of the facts together, setTimeout by default is designed to hold the event loop open (so if that's the only thing pending, the program will wait). You can programmatically disable or re-enable the behavior.
Late answer, but a definite yes - Nodejs will wait around for setTimeout to finish - see this documentation. Coincidentally, there is also a way to not wait around for setTimeout, and that is by calling unref on the object returned from setTimeout or setInterval.
To summarize: if you want Nodejs to wait until the timeout has been called, there's nothing you need to do. If you want Nodejs to not wait for a particular timeout, call unref on it.
If node didn't wait for all setTimeout or setInterval calls to complete, you wouldn't be able to use them in simple scripts.
Once you tell node to listen for an event, as with the setTimeout or some async I/O call, the event loop will loop until it is told to exit.
Rather than wrap everything in a try/catch you can bind an event listener to process just as the example in the docs:
process.on('uncaughtException', function(err) {
console.log('Caught exception: ' + err);
});
setTimeout(function() {
console.log('This will still run.');
}, 500);
// Intentionally cause an exception, but don't catch it.
nonexistentFunc();
console.log('This will not run.');
In the uncaughtException event, you can then add a setTimeout to exit after 10 seconds:
process.on('uncaughtException', function(err) {
console.log('Caught exception: ' + err);
setTimeout(function(){ process.exit(1); }, 10000);
});
If this exception is something you can recover from, you may want to look at domains: http://nodejs.org/api/domain.html
edit:
There may actually be another issue at hand: your client application doesn't do enough (or any?) logging. You can use log4js-node to write to a temp file or some application-specific location.
Easy way Solution:
Make a batch (.bat) file that starts nodejs
make a shortcut out of it
Why this is best. This way you client would run nodejs in command line. And even if nodejs program returns nothing would happen to command line.
Making bat file:
Make a text file
put START cmd.exe /k "node abc.js"
Save it
Rename It to abc.bat
make a shortcut or whatever.
Opening it will Open CommandLine and run nodejs file.
using settimeout for this is a bad idea.
The odd ones out are when you call process.exit() or there's an uncaught exception, as pointed out by Jim Schubert. Other than that, node will wait for the timeout to complete.
Node does remember timers, but only if it can keep track of them. At least that is my experience.
If you use setTimeout in an arrow / anonymous function I would recommend to keep track of your timers in an array, like:
=> {
timers.push(setTimeout(doThisLater, 2000));
}
and make sure let timers = []; isn't set in a method that will vanish, so i.e. globally.