So, I'm making this request to a server and I set a timeout and I want to handle the timeout event, but I also want to handle the 'abort' event and differ one for another. I managed to do it with a quick fix, but I wanted to know if there is a better way to do it. The code looks like this:
makeRequest = function(json, cb){
var requestError
request({
url: REQUEST_URL,
json: json,
timeout: 3000,
headers: {
'Content-Type': 'application/json'
}
}, function(err, res, body){
if(err) requestError = err
else cb(null, res, body)
}).on('abort', function(){
setTimeout(function({
if(requestError != 'ETIMEDOUT') cb(httpStatusCode.REQUEST_TIMEDOUT)
else cb(httpStatusCode.REQUEST_ABORTED
}, 1000)
})
}
I noticed that in the timeout event both the 'abort' event is triggered and the request callback is called, in this order, so I used the setTimeout function to wait for the request callback and than handle the error in the 'abort' listener. This seems like a dumb way to do it and I searched online and did not find a way yo handle only the callback event. I also noticed that the timeout triggers the on.('error', function(err){}) event, where I can handle the error, but it also calls the on.('abort', function(){}) event and I end up calling the main callback (cb) two times, crashing my application.
Is there a way I can have an event ONLY for the timeout and one ONLY for the abort, so I don't have to use setTimeout?
Or is there any property in my req object that I can check to see if that request timed out or not?
Or do you have any other suggestion to fix my problem in a less ugly way?
I'm using nodejs 0.12.2 and request 2.55.0 Thanks!
One great thing about open source is that you can always just go look at the code for the module and see how it works.
If you want the error, then just listen for .on('error', function(err) {})
. The error will be passed there. The .on('abort', function() {})
event does not tell you why it was aborted. But, as you can see from the relevant source code for the request module, the error
event is always sent right after the abort
event and it will have e.code
set to ETIMEDOUT
.
Here's a copy of some of the relevant source code for when .abort()
is called where you can see it triggers the error event right afterwards:
if (self.timeout && !self.timeoutTimer) {
var timeout = self.timeout < 0 ? 0 : self.timeout
self.timeoutTimer = setTimeout(function () {
self.abort()
var e = new Error('ETIMEDOUT')
e.code = 'ETIMEDOUT'
self.emit('error', e)
}, timeout)
// Set additional timeout on socket - in case if remote
// server freeze after sending headers
if (self.req.setTimeout) { // only works on node 0.6+
self.req.setTimeout(timeout, function () {
if (self.req) {
self.req.abort()
var e = new Error('ESOCKETTIMEDOUT')
e.code = 'ESOCKETTIMEDOUT'
self.emit('error', e)
}
})
}
}
So, it seems you can ignore the abort
event and just listen for the error
event and just call your callback on the error
event.
If your code is such that it messes up if the callback is called with an error more than once (which it sounds like it is), then you can change your makeRequest()
function so that it never calls the callback more than once too.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With