How to debug a socket hang up error in NodeJS? - node.js

I am getting the following error:
events.js:48
throw arguments[1]; // Unhandled 'error' event
^
Error: socket hang up
at createHangUpError (http.js:1091:15)
at Socket.onend (http.js:1154:27)
at TCP.onread (net.js:363:26)
In node v0.6.6, my code has multiple http.request and .get calls.
Please suggest ways to track what causes the socket hang up, and on which request/call it is.
Thank you

Quick and dirty solution for development:
Use longjohn, you get long stack traces that will contain the async operations.
Clean and correct solution:
Technically, in node, whenever you emit an 'error' event and no one listens to it, it will throw. To make it not throw, put a listener on it and handle it yourself. That way you can log the error with more information.
To have one listener for a group of calls you can use domains and also catch other errors on runtime. Make sure each async operation related to http(Server/Client) is in different domain context comparing to the other parts of the code, the domain will automatically listen to the error events and will propagate it to its own handler. So you only listen to that handler and get the error data. You also get more information for free.(Domains are depreceated).
As Mike suggested you can also set NODE_DEBUG=net or use strace. They both provide you what is node doing internally.

Additionally, you can set the NODE_DEBUG environment variable to net to get information about what all the sockets are doing. This way you can isolate which remote resource is resetting the connection.

In addition to ftft1885's answer
http.get(url, function(res)
{
var bodyChunks = [];
res.on('data', function(chunk)
{
// Store data chunks in an array
bodyChunks.push(chunk);
}).on('error', function(e)
{
// Call callback function with the error object which comes from the response
callback(e, null);
}).on('end', function()
{
// Call callback function with the concatenated chunks parsed as a JSON object (for example)
callback(null, JSON.parse(Buffer.concat(bodyChunks)));
});
}).on('error', function(e) {
// Call callback function with the error object which comes from the request
callback(e, null);
});
When I had this "socket hang up" error, it was because I wasn't catching the requests errors.
The callback function could be anything; it all depends on the needs of your application. Here's an exemple of a callback logging data with console.log and logging errors with console.error:
function callback(error, data) {
if (error) {
console.error('Something went wrong!');
console.error(error);
}
else {
console.log('All went fine.');
console.log(data);
}
}

use
req.on('error',function(err){})

Most probably your server socket connection was somehow closed before all http.ServerResponse objects have ended. Make sure that you have stopped all incoming requests before doing something with incoming connections (incomming connection is something different than incoming HTTP request).

Related

Getting "Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client" while using Axios

I am trying to use different Axios calls to get some data from a remote server. One by one the calls are working but as soons as I call them directly after each other its throwing the error message about the headers. I did some research already and I guess it has sth to do that there the headers of the first call gets in the way of the second call. That is probably a very simplematic description of the problem but I am new to node js and the way those axios calls are working.
This is an example of one of my Api calls:
app.get('/api/ssh/feedback', function(req, res){
conn.on('ready', function(){
try {
let allData = {}
var command = 'docker ps --filter status=running --format "{{.Names}}"'
conn.exec(command, function(err, stream){
if (err) throw console.log(err)
stream.on('data', function(data){
allData = data.toString('utf8').split('\n').filter(e=>e)
return res.json({status: true, info: allData})
})
stream.on('close', function(code){
console.log('Process closed with: ' + code)
conn.end()
})
stream.on('error', function(err){
console.log('Error: ' + err)
conn.end()
})
})
} catch (err) {
console.error('failed with: ' + err)
}
}).connect(connSet)
})
I am using express js as a middleware and the shh2 package to get the connection with the remote server. How I mentioned before the call is working but crashes if it is not the first call. I am able to use the api again after I restart the express server.
This is how I am calling the api through axios in my node js frontend:
getNetworkStatus(e){
e.preventDefault()
axios.get('/api/ssh/network').then(res =>{
if(res.data.status){
this.setState({network_info: 'Running'})
this.setState({network: res.data.info})
} else {
this.setState({network_info: 'No Network Running'})
this.setState({network: 'No Network detected'})
}
}).catch(err => {
alert(err)
})
}
I would be really grateful for any help or advice how to solve this problem. Thanks to everyone who spends some time to help me out.
There are two issues in the code you've provided:
You are making assumptions about 'data' events. In general, never assume the size of the chunks you receive in 'data' events. You might get one byte or you might get 1000 bytes. The event can be called multiple times as chunks are received and this is most likely what is causing the error. Side note: if the command is only outputting text, then you are better off using stream.setEncoding('utf8') (instead of manually calling data.toString('utf8')) as it will take care of multi-byte characters that may be split across chunks.
You are reusing the same connection object. This is a problem because you will continue to add more and more event handlers every time that HTTP endpoint is reached. Move your const conn = ... inside the endpoint handler instead. This could also be causing the error you're getting.

How to catch node TimeoutError and log the request?

I'm writing an application in node in which I do many websocket requests to a remote service (using the ws library). So the remote service is the server, and my node application is the client. It works quite well, but occasionally I suddenly get a long list of the following TimeoutError:
Unhandled rejection TimeoutError: ResourceRequest timed out
at ResourceRequest._fireTimeout (/Users/kramer65/repos/mmj/node_modules/generic-pool/lib/ResourceRequest.js:58:17)
at Timeout.bound (/Users/kramer65/repos/mmj/node_modules/generic-pool/lib/ResourceRequest.js:8:15)
at ontimeout (timers.js:386:11)
at tryOnTimeout (timers.js:250:5)
at Timer.listOnTimeout (timers.js:214:5)
Since I do many different websocket calls I now wonder for which call this error occurs. I tried wrapping the ws.send() in a try/catch as I pasted below, but that doesn't seem to do anything.
try {
ws.send(request_json);
} catch(e) {
console.log('WEBSOCKET ERROR', e);
console.log('WEBSOCKET JSON', request_json);
}
Does anybody know how I can catch the TimeoutError and log the request contents? All tips are welcome!
[EDIT]
As suggested by #Mark_M I added a callback to the ws.send() method as follows:
ws.send(JSON.stringify(request_obj)), (error)=>{
console.log('WEBSOCKET ERROR', request_obj.action, error);
});
Unfortunately I still get the same errors as I posted on the top of this question.
[EDIT2]
I also tried the suggestion made by #wrangler:
ws.send(JSON.stringify(request_obj));
ws.onerror = function(event) {
console.log('WEBSOCKET ONERROR', request_obj.action, event);
};
ws.onclose = function (event){
console.log('WEBSOCKET ONCLOSE', request_obj.action, event);
};
but unfortunately this also doesn't seem to work. I still get the same errors as I posted on the top of this question.
Any other ideas?
The ws.library send() method takes an optional callback that will be called when it encounters an error. You can catch those errors with:
ws.send('something', function ack(error) {
if(error) //handle error
}
Try/catch will catch immediate errors, but, as you noticed, it doesn't help with async errors.
Alternatively, it looks like you are calling send() within some other async code (because you aren't just getting an error, you're getting an unhandled promise rejection). You could add a .catch() onto that promise if it's in your own code.
You can use onerror callback of websocket object for receiving any error.
Example:
var exampleSocket = new WebSocket("ws://echo.websocket.org");
exampleSocket.onopen = function (event) {
console.log("open");
exampleSocket.send("hellow world");
};
exampleSocket.onmessage = function (event) {
console.log(event.data);
}
exampleSocket.onerror=function(event){
console.log("Error");
}
Link:http://jsfiddle.net/g28yuymv/1/
Link2:http://jsfiddle.net/g28yuymv/10/
Ok, stupid me. After looking at the initial error a bit better I found that it was an error in the generic-pool package. On its npm page it says it's
a Promise based API, which can be used to reuse or throttle usage of
expensive resources such as database connections
The problem turned out to be my database connection (which is used extensively). I solved it using this tip on github, which suggests to set the sequelize init pool settings as follows:
pool: {max: 5, min: 0, idle: 20000, acquire: 20000}
That solved it for me.
Thanks to the answers, I now have proper websocket error reporting though.. :-)

Does req.abort() always trigger error event in node.js?

Like the title says...
I use the HTTPS module for nodejs and when making requests I set timeout and attach an error listener.
req.setTimeout(6000, function(){
// mark_completed(true);
this.abort();
})
.on('error', function (e){
if (!this.aborted){
// mark_completed(true);
console.log(e);
}
});
In both scenarios I want to execute a function to mark my request as completed.
Is it safe to assume that on error will always be triggered after after the timeout, so that I can place my function exclusively inside the on error event?

listening for emitted error on fs.createReadStream

If I understand Node correctly, a listener will only receive events that occur after it's attached. Suppose missing.txt is a missing file. This works:
'use strict';
const fs = require( 'fs' );
var rs = fs.createReadStream( 'missing.txt' );
rs.on('error', (err) => console.log('error ' + err) );
It produces: error Error: ENOENT: no such file or directory, open ...\missing.txt
Why does that work? Changing the fourth line as follows also works:
setTimeout( () => rs.on('error', (err) => console.log('error ' + err)) , 1);
But change the timeout to 5ms, and the error is thrown as an unhandled event.
Am I setting up a race that happens to catch the emitted error if the delay to add the event listener is short enought? Does that mean I really should do an explicit check for the existence of the file before opening it as a stream? But that could create another race, as the Node docs state with respect to fs.exists: "other processes may change the file's state between the two calls."
Moroeover, the event listener is convenient because it will catch other errors.
Is it best practice to just assume that, without introducing an explicit delay, the event listener will be added fast enough to hear an error from attempting to stream a non-existent file?
This error occur when there no such location exists or creating permission are not with user program.
This might be helpful:
var filename = __dirname+req.url;
var readStream = fs.createReadStream(filename);
readStream.on('open', function () {
readStream.pipe(res);
});
readStream.on('error', function(err) {
res.end(err);
});
Why are you listening error on timeout ?
Thanks
Any errors that occur after getting a ReadStream instance from fs.createReadStream() will not be thrown/emitted until at least the next tick. So you can always attach the 'error' listener to the stream after creating it so long as you do so synchronously. Your setTimeout experiment works sometimes because the ReadStream will call this.open() at the end of its constructor. The ReadStream.prototype.open() method calls fs.open() to get a file descriptor from the file path you provided. Since this is also an asynchronous function it means that when you attach the 'error' listener inside a setTimeout you are creating a race condition.
So it comes down to which happens first, fs.open() invoking its callback with an error or your setTimeout() invoking its callback to attach the 'error' listener. It is completely fine to attach your 'error' listener after creating the ReadStream instance, just be sure to do it synchronously and you won't have a problem with race conditions.

Node.js Error Sending Stream to Mplayer, Sending File Works Fine

I'm trying to spawn mplayer as a child process, sometimes with a file to play and other times with a stream to play. The file works fine, but when I create a stream from the file, I get this error:
events.js:85
throw er; // Unhandled 'error' event
^
Error: read ECONNRESET
at exports._errnoException (util.js:746:11)
at Pipe.onread (net.js:550:26)
It's not a file permissions problem because I ran it as sudo and still had the same issue.
To test a potential problem with streaming, I created a write stream from the read stream and that worked without a problem.
I'm not really sure what to do next. I'd appreciate any advice or help.
Here's the code:
var fs = require('fs');
var spawn = require('child_process').spawn;
var file = "/usr/local/apps/ha6/web/voice/ga.wav";
var file2 = "/usr/local/apps/ha6/web/voice/ga2.wav";
function filePlay() {
var mplayer = spawn("mplayer", ["-slave", file], {stdio: ['pipe', 'ignore', 'ignore']});
mplayer.on("exit", function () {
console.log("exit");
});
}
function streamPlay() {
var str = fs.createReadStream(file).on("error", function (error) {
console.log("Error creating read stream:" + error);
});
var mplayer = spawn("mplayer", ["-slave "], {stdio: ['pipe', 'ignore', 'ignore']}).on("error", function (error) {
console.log("Spawn error " + error);
});
str.pipe(mplayer.stdin);
}
function testPiping() {
var str = fs.createReadStream(file).on("error", function (error) {
console.log("Error creating read stream:" + error);
});
var str2 = fs.createWriteStream(file2).on("error", function(error) {
console.log("Error creating write stream:" + error);
});
str.pipe(str2);
console.log("Pipe a success!");
}
filePlay(); // works fine
testPiping(); // works fine
streamPlay(); // ECONNRESET error
I would guess that the reason the error looks so bad is that there's an underlying problem with net.Socket.on as seen here and the code was revised here. So joyent appears to be the code that's in the underlying error. My attempt above was to make a catch-all error trapper that "swallows" the error and puts it into the log.
What is TCP RST? Read about it here. Sometimes a router or your ISP wants to validate that an open TCP connection is still listening and so they inject a reset. Your app's stack is expected to respond in such a way to satisfy them not to drop the session.
Shorter answer: try upgrading the joyent module to latest.
From this answer, "Clean and correct solution: Technically, in node, whenever you emit an 'error' event and no one listens to it, it will throw. To make it not throw, put a listener on it and handle it yourself. That way you can log the error with more information.", the suggestion is to listen (trap) the error so that it doesn't throw an exception. Joyent is throwing the error. If you don't catch it (trap it) then it rises to the level of destruction.
Try
stream.on("error", function(e) { console.log(e); });
...somewhere before the call. You're basically separating the error logic from the stream itself. If the child process isn't running yet or has closed before the parent calls then there's no binding. <- Guess

Resources