I have two options to set a timeout to my http request. I am not sure about their difference.
First one is:
req.setTimeout(2000,function () {
req.abort();
console.log("timeout");
self.emit('pass',message);
});
Second one is:
req.on('socket', function (socket) {
socket.setTimeout(2000);
socket.on('timeout', function() {
req.abort();
self.emit('pass',message);
});
}
socket.setTimeout sets the timeout for the socket, e.g. to implement HTTP Keep-Alive.
request.setTimeout does internally call socket.setTimeout, as soon as a socket has been assigned to the request and has been connected. This is described in the documentation.
Hence, it's no difference, and you can choose which way to go. Of course, if you already have a request in your hands, you'd stick to the request's setTimeout function instead of digging for the underlying socket.
Related
I have some tests which bind to a UDP port, e.g.
describe('the server', function() {
it('should respond to a udp packet', function(done) {
const udp = dgram.createSocket('udp4');
udp.on('error', function(error) {
console.log(error);
});
udp.on('message', function(msg, rinfo) {
console.log('msg', msg);
console.log('rinfo', rinfo);
// TODO: check the reply
udp.close();
done();
});
udp.bind();
// send a request
const bytes = Buffer.from("421a0800117860bc457f0100001a0653455256455222054d54303031", 'hex');
udp.send(bytes, SERVER_PORT, SERVER_ADDR)
});
});
When the test completes successfully, that code path can call udp.close() which lets mocha exit.
When a test exceeds mocha's 2 second time-out, I see the error but mocha does not exit as the UDP port is still listening.
Is there some form of callback/event that I can use to close a listening UDP socket when mocha's 2 second time-out fires?
This can be achieved with an afterEach hook. An afterEach hook is a function that gets executed after each test, whether passed or failed (but not skipped). So it is useful to perform cleanup operations, like closing a socket in this case.
Like all Mocha hooks, an afterEach is defined inside a describe function call, and it applies to all tests in that scope. If you only want the hook to run after one particular test only, put that test into a dedicated describe function.
So the changes to do here are the following:
Move the declaration of udp from the it function into the containing describe function. This will make udp accesible from both it and afterEach.
Add an afterEach hook to perform the cleanup operation: udp.close();. Remember that this will run whether the test passes or fails for any reason, so it's a good idea to avoid assumptions about the progress of the test. Here: don't assume that udp has been already created.
Remove other calls to udp.close();, these are no longer needed now.
describe('the server', function() {
let udp;
afterEach(() => {
if (udp) {
udp.close();
udp = undefined;
}
});
it('should respond to a udp packet', function(done) {
udp = dgram.createSocket('udp4');
udp.on('error', function(error) {
console.log(error);
});
udp.on('message', function(msg, rinfo) {
console.log('msg', msg);
console.log('rinfo', rinfo);
// TODO: check the reply
done();
});
udp.bind();
// send a request
const bytes = Buffer.from("421a0800117860bc457f0100001a0653455256455222054d54303031", 'hex');
udp.send(bytes, SERVER_PORT, SERVER_ADDR)
});
});
One thing to note is that in case of a timeout, the test function may keep running after the socket has been closed, producing all kinds of baffling error messages: this is not surprising.
Another interesting thing to note is that variables scoped in a describe function call (unlike those in an it function call) have the same lifetime of the Mocha run. For this reason it is a common practice to create those variable lazily when needed (in the tests) and to clear up manually by setting them explicitly to undefined or null as soon as they are no longer needed.
You can also use mocha --exit which is far simpler than closing the sockets yourself.
When using redis client (ioredis or node_redis) inside websocket's message event in a nodejs app, the callback for any command is not immediately fired. (the operation does take place on redis server though)
What is strange is that the callback for the first command will fire after i sent a second message, and the callback for the second will fire after i send a third.
wss.on('connection', (socket, request) => {
socket.on('message', (data) => {
console.log("will send test command")
this.pubClient.hset("test10", "f1","v1", (err,value) => {
//callback not firing first time
console.log("test command reply received")
})
})
}
the redis command is working as expected though in other parts of the app and even when inside the on connection directly like below.
wss.on('connection', (socket, request) => {
console.log("will send test command")
this.pubClient.hset("test10", "f1","v1", (err,value) => {
//callback fires
console.log("test command reply received")
})
socket.on('message', (data) => {})
}
UPDATE:
I had this all wrong. The reason for the weird callback behavior is the result of one my custom Redis modules not returning a reply.
And this seems to have caused all callbacks after this call to seem to have some kind of a one step delay.
I had this all wrong. The reason for the weird callback behavior is the result of one my custom Redis modules not returning a reply. And this seems to have caused all callbacks after this call to seem to have some kind of a one step delay.
I know I am overthinking this... but the answer is just not clicking.
I have two servers, one a TCP socket server and the other a SockJS server. I need to combine both of their connection events into one super event:
async.parallel({
tcp: function (done) {
self._tcp = net.createServer(function (sock) {
done(null, sock);
});
},
ws: function (done) {
self._ws = sockjs.createServer(function (sock) {
done(null, sock);
});
}
}, function (err, results) {
// This never gets fired!!!
// But I'd like to do stuff here with both
// socket instances – you know, like piping =)
});
Originally I had the TCP connection nested within the WS connection, but that's proving to be problematic as it requires a rigid connection sequence. What I really need is an event that is fired when both connections have been established and have access to their respective sock instances. Help jogging the brain would be much appreciated!
This might be overly simple - but looking at the sockjs documentation, there isn't a callback function for createServer() - so it's never going to loop back through the callback of your parallel function.
Try just calling done(null, sock); right after you do socket.createServer(); and you should be all set.
Doc: https://github.com/sockjs/sockjs-node
I have code to log every connection to my HTTP-server on a socket level and also log any incoming data.
This code was originally written for NodeJS 0.8 and works good there.
No my project is migrated to 0.10.24 and socket logging code stopped working.
Here is my code:
var netLogStream = fs.createWriteStream('net.log');
(function(f) {
net.Server.prototype.listen = function(port) {
var rv = f.apply(this, arguments); // (1)
rv.on('connection', function(socket) { // (2)
socket.on('data', function(data) {
data.toString().split('\n').forEach(function(line) { // (3)
netLogStream.write('... some logging here ... ' + line);
});
});
});
return rv;
};
})(net.Server.prototype.listen);
On 0.10 I can get to (1) and get Socket instance on (2) but I never get to (3). Same time my whole application works fine without any issues.
ADD: My server is created with Express#3.4.x
I'm not sure why the results are different between node v0.8 and v0.10, but if I had to guess, I'd be looking at the return value of net.Server.prototype.listen.
According to the documentation, this is an asynchronous method which emits the 'listen' event and invokes its callback when the listening is bound. You're not looking for that event, but rather, capturing the return value of listen, which for an async function, may not be well-defined. It's obviously not null or undefined since you don't get a runtime error, but the return value may not be the same between v0.8 and v0.10.
I honestly don't know for sure because I don't do low-level socket coding, but I have 2 suggestions to try:
Since the connection event is emitted from the Server object, perhaps you need this.on instead of rv.on.
Setup the connection event listener before you invoke listen just to minimize risk of race conditions.
Try this and see what happens:
var netLogStream = fs.createWriteStream('net.log');
(function(f) {
net.Server.prototype.listen = function(port) {
this.on('connection', function(socket) { // (2)
socket.on('data', function(data) {
data.toString().split('\n').forEach(function(line) { // (3)
netLogStream.write('... some logging here ... ' + line);
});
});
});
return f.apply(this, arguments); // (1)
};
})(net.Server.prototype.listen);
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).