Skip to content


Subversion checkout URL

You can clone with
Download ZIP


timeout event, and timeout option implemented. added docs & example #130

merged 2 commits into from

5 participants


I was serially testing GET's on a million websites, and gradually came across my test app stalling with the same pattern.

It turned out that restler has/had no option for timeout. This is a show-stopper for large/production scenarios.

eg: The following code, stalls forever, without throwing an error or

  rest.get('').on('complete', function(){ 
    console.log('never entered here');

infact it did not emit any known events either. namely error or abort.

 rest.get('').on('error' function(ms){
   sys.puts('neither found an error');
  }).on('abort' function(ms){
   sys.puts('nor an abort');
   sys.puts('never reached here either');

I also saw previous mentions requesting timeout feature for restler.
eg: #3 one of the oldest open bugs/issues.

So i went ahead, forked and fixed this.

My commit includes :

  • added the 'timeout' event
  • added the {timeout:Ms} option
  • added documentation for timeout
  • added an example for timeout

Here's an example.

 rest.get('',{timeout: 10000}).on('timeout' function(ms){
   sys.puts('did not return within '+ms+' ms');
   sys.puts('life goes on');

Will love to see this reviewed for a possible merge.

~Bosky @bhaskerkode






I'm happy to merge this with some tests. Any chance you could knock some up?

@easternbloc easternbloc merged commit 0ca56f7 into danwrong:master
@easternbloc easternbloc referenced this pull request

Feature/timeout tests #144

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
Showing with 29 additions and 0 deletions.
  1. +8 −0
  2. +21 −0 lib/restler.js
@@ -43,6 +43,7 @@ Basic method to make a request of any type. The function returns a RestRequest o
* `fail: function(data, response)` - emitted when the request was successful, but 4xx status code returned. Gets passed the response data and the response object as arguments.
* `error: function(err, response)` - emitted when some errors have occurred (eg. connection aborted, parse, encoding, decoding failed or some other unhandled errors). Gets passed the `Error` object and the response object (when available) as arguments.
* `abort: function()` - emitted when `request.abort()` is called.
+* `timeout: function(ms)` - when a request takes more than the timeout option eg: {timeout:5000}, the request will be aborted. error and abort events will not be called, instead timeout will be emitted.
* `2XX`, `3XX`, `4XX`, `5XX: function(data, response)` - emitted for all requests with response codes in the range (eg. `2XX` emitted for 200, 201, 203).
* <code><i>actual response code</i>: function(data, response)</code> - emitted for every single response code (eg. 404, 201, etc).
@@ -113,6 +114,7 @@ Also you can use `json()` and `postJson()` methods.
* `multipart` If set the data passed will be formated as `multipart/form-encoded`. See multipart example below. Defaults to `false`.
* `client` A http.Client instance if you want to reuse or implement some kind of connection pooling. Defaults to empty.
* `followRedirects` If set will recursively follow redirects. Defaults to `true`.
+* `timeout` If set, will emit the timeout event when the response does not return within the said value (in ms)
Example usage
@@ -139,6 +141,12 @@ rest.get('').on('complete', function(da
sys.puts(data[0].sounds[0].sound[0].message); // auto convert to object
+rest.get('',{timeout: 10000}).on('timeout' function(ms){
+ sys.puts('did not return within '+ms+' ms');
+ sys.puts('did not time out');
+'', {
data: { id: 334 },
}).on('complete', function(data, response) {
21 lib/restler.js
@@ -206,9 +206,22 @@ mixin(Request.prototype, {
_fireError: function(err, response) {
+ this._fireCancelTimeout();
this.emit('error', err, response);
this.emit('complete', err, response);
+ _fireCancelTimeout: function(){
+ var self = this;
+ if(self.options.timeout){
+ clearTimeout(self.options.timeoutFn);
+ }
+ },
+ _fireTimeout: function(err){
+ this.emit('timeout', err);
+ this.aborted = true;
+ this.timedout = true;
+ this.request.abort();
+ },
_fireSuccess: function(body, response) {
if (parseInt(response.statusCode) >= 400) {
this.emit('fail', body, response);
@@ -221,10 +234,18 @@ mixin(Request.prototype, {
_makeRequest: function() {
var self = this;
+ var timeoutMs = self.options.timeout;
+ if(timeoutMs){
+ self.options.timeoutFn = setTimeout(function(){
+ self._fireTimeout(timeoutMs);
+ },timeoutMs);
+ }
this.request.on('response', function(response) {
+ self._fireCancelTimeout();
self.emit('response', response);
}).on('error', function(err) {
+ self._fireCancelTimeout();
if (!self.aborted) {
self._fireError(err, null);
Something went wrong with that request. Please try again.