Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Expotential backoff for reconnection #617

Closed
wants to merge 10 commits into from

3 participants

@poohlty

Discussion branch for now, not for immediate merge yet!

Contains basic logic for using exponential back-off, instead of delay for reconnection. Still lacks proper documentation/clean up for the old delay logic. @guille @defunctzombie

@get
get commented

:thumbsup:

@rauchg
Owner

Needs docs.

@poohlty

Just added some docs for new methods :)

@poohlty

@guille The API now allows user to pass in a custom back off method. Exponential back off is used by default

@rauchg
Owner

Did you document the readme? That's key

@poohlty

Terribly sorry for the delay, last week was kinda crazy for me for all the quizzes and make-up works :( So it seems that the change in code affect the interface, basically that several constants for delay are no longer needed. Instead, some other ones for exp back off are used. Should I just delete those getter/setter method for delay constants, and update them to the new ones for exp back off?

README.md
((6 lines not shown))
- `timeout` connection timeout before a `connect_error`
and `connect_timeout` events are emitted (`10000`)
+ - `initialDelay` how long is the first delay, default is 1000 (`1000`)
+ - `backoffMultipler` how much should be multiplied to increase the delay time, default is 1.5 (`1.5`)
+ - `randomizeFactor` how much should the multiplied time be randomized default is (`0`)
+ - `backoffMethod` a fuction that returns the backoff method of delays (`function(){ return 1000; }`)
@rauchg Owner
rauchg added a note

Please prefix all the options with reconnection. Otherwise initialDelay for example is too generic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@poohlty

@guille do I need more updates on this? Or is it good to merge? :P

@poohlty

@guille I think the branch is good to merge now! :v:

This issue was closed.
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 119 additions and 26 deletions.
  1. +27 −10 README.md
  2. +82 −16 lib/manager.js
  3. +10 −0 test/connection.js
View
37 README.md
@@ -84,13 +84,15 @@ Socket.IO is compatible with [browserify](http://browserify.org/).
Options:
- `reconnection` whether to reconnect automatically (`true`)
- - `reconnectionDelay` how long to wait before attempting a new
- reconnection (`1000`)
- `reconnectionDelayMax` maximum amount of time to wait between
reconnections (`5000`). Each attempt increases the reconnection by
- the amount specified by `reconnectionDelay`.
+ the amount specified by the return value (in ms) of `reonnectionBackoffMethod`, which uses exponential back off as default.
- `timeout` connection timeout before a `connect_error`
and `connect_timeout` events are emitted (`20000`)
+ - `reconnectionInitialDelay` how long is the first delay, default is 1000 (`1000`)
+ - `reconnectionBackoffMultipler` how much should be multiplied to increase the delay time, default is 1.5 (`1.5`)
+ - `reconnectionRandomizeFactor` how much should the multiplied time be randomized default is (`0`)
+ - `reconnectionBackoffMethod` a fuction that returns the backoff method of delays (`function(){ return 1000; }`)
#### Events
@@ -115,24 +117,39 @@ reconnect that depend on this `Manager`.
Sets the `reconnection` option, or returns it if no parameters
are passed.
-### Manager#reconnectionAttempts(v:Boolean):Manager
+### Manager#reconnectionAttempts(v:Integer):Manager
Sets the `reconnectionAttempts` option, or returns it if no parameters
are passed.
-### Manager#reconnectionDelay(v:Boolean):Manager
+### Manager#reconnectionDelayMax(v:Integer):Manager
- Sets the `reconectionDelay` option, or returns it if no parameters
+ Sets the `reconnectionDelayMax` option, or returns it if no parameters
are passed.
-### Manager#reconnectionDelayMax(v:Boolean):Manager
+### Manager#timeout(v:Integer):Manager
- Sets the `reconectionDelayMax` option, or returns it if no parameters
+ Sets the `timeout` option, or returns it if no parameters
are passed.
-### Manager#timeout(v:Boolean):Manager
+### Manager#reconnectionInitialDelay(v:Integer):Manager
- Sets the `timeout` option, or returns it if no parameters
+ Sets the `reconnectionInitialDelay` option, or returns it if no parameters
+ are passed.
+
+### Manager#reconnectionBackoffMultipler(v:Float):Manager
+
+ Sets the `reconnectionBackoffMultipler` option, or returns it if no parameters
+ are passed.
+
+### Manager#reconnectionRandomizeFactor(v:Float):Manager
+
+ Sets the `reconnectionRandomizeFactor` option, or returns it if no parameters
+ are passed.
+
+### Manager#reconnectionBackoffMethod(v:Function):Manager
+
+ Sets the `reconnectionBackoffMethod` option, or returns it if no parameters
are passed.
### Socket
View
98 lib/manager.js
@@ -41,8 +41,13 @@ function Manager(uri, opts){
this.opts = opts;
this.reconnection(opts.reconnection !== false);
this.reconnectionAttempts(opts.reconnectionAttempts || Infinity);
- this.reconnectionDelay(opts.reconnectionDelay || 1000);
this.reconnectionDelayMax(opts.reconnectionDelayMax || 5000);
+
+ this.reconnectionInitialDelay(opts.reconnectionInitialDelay || 1000);
+ this.reconnectionBackoffMultipler(opts.reconnectionBackoffMultipler || 1.5);
+ this.reconnectionRandomizeFactor(opts.reconnectionRandomizeFactor || 0);
+ this.reconnectionBackoffMethod(opts.reconnectionBackoffMethod || this.expBackoff);
+
this.timeout(null == opts.timeout ? 20000 : opts.timeout);
this.readyState = 'closed';
this.uri = uri;
@@ -90,43 +95,85 @@ Manager.prototype.reconnectionAttempts = function(v){
};
/**
- * Sets the delay between reconnections.
+ * Sets the maximum delay between reconnections.
*
* @param {Number} delay
* @return {Manager} self or value
* @api public
*/
-Manager.prototype.reconnectionDelay = function(v){
- if (!arguments.length) return this._reconnectionDelay;
- this._reconnectionDelay = v;
+Manager.prototype.reconnectionDelayMax = function(v){
+ if (!arguments.length) return this._reconnectionDelayMax;
+ this._reconnectionDelayMax = v;
return this;
};
/**
- * Sets the maximum delay between reconnections.
+ * Sets the connection timeout. `false` to disable
*
- * @param {Number} delay
* @return {Manager} self or value
* @api public
*/
-Manager.prototype.reconnectionDelayMax = function(v){
- if (!arguments.length) return this._reconnectionDelayMax;
- this._reconnectionDelayMax = v;
+Manager.prototype.timeout = function(v){
+ if (!arguments.length) return this._timeout;
+ this._timeout = v;
return this;
};
/**
- * Sets the connection timeout. `false` to disable
+ * Sets the initial delay time for the first reconnection.
*
+ * @param {Number} initial delay time for the first reconnection
* @return {Manager} self or value
* @api public
*/
-Manager.prototype.timeout = function(v){
- if (!arguments.length) return this._timeout;
- this._timeout = v;
+Manager.prototype.reconnectionInitialDelay = function(v){
+ if (!arguments.length) return this._reconnectionInitialDelay;
+ this._reconnectionInitialDelay = v;
+ return this;
+};
+
+/**
+ * Sets the backoff multipler for delay intervals between reconnect attempts.
+ *
+ * @param {Number} backoff multiper
+ * @return {Manager} self or value
+ * @api public
+ */
+
+Manager.prototype.reconnectionBackoffMultipler = function(v){
+ if (!arguments.length) return this._reconnectionBackoffMultipler;
+ this._reconnectionBackoffMultipler = v;
+ return this;
+};
+
+/**
+ * Sets the randomization factor for delay intervals.
+ *
+ * @param {Number} randomization factor
+ * @return {Manager} self or value
+ * @api public
+ */
+
+Manager.prototype.reconnectionRandomizeFactor = function(v){
+ if (!arguments.length) return this._reconnectionRandomizeFactor;
+ this._reconnectionRandomizeFactor = v;
+ return this;
+};
+
+/**
+ * Sets the backoff method for delay intervals.
+ *
+ * @param {Fuction} Backoff Method
+ * @return {Manager} self or value
+ * @api public
+ */
+
+Manager.prototype.reconnectionBackoffMethod = function(v){
+ if (!arguments.length) return this._reconnectionBackoffMethod;
+ this._reconnectionBackoffMethod = v;
return this;
};
@@ -383,6 +430,25 @@ Manager.prototype.onclose = function(reason){
};
/**
+ * Calculate delay time using exponential backoff.
+ *
+ * @api private
+ */
+
+Manager.prototype.expBackoff = function(scope){
+ var multipler = scope.reconnectionBackoffMultipler();
+ var reconnectionRandomizeFactor = scope.reconnectionRandomizeFactor();
+
+ var interval = (multipler ^ scope.attempts) * scope.reconnectionInitialDelay();
+
+ var min = (1 - reconnectionRandomizeFactor) * interval;
+ var max = (1 + reconnectionRandomizeFactor) * interval;
+ var delay = (max - min) * Math.random() + min;
+
+ return Math.min(delay, scope.reconnectionDelayMax());
+};
+
+/**
* Attempt a reconnection.
*
* @api private
@@ -399,8 +465,8 @@ Manager.prototype.reconnect = function(){
this.emit('reconnect_failed');
this.reconnecting = false;
} else {
- var delay = this.attempts * this.reconnectionDelay();
- delay = Math.min(delay, this.reconnectionDelayMax());
+ var currentBackoffMethod = this.reconnectionBackoffMethod();
+ var delay = currentBackoffMethod(self);
debug('will wait %dms before reconnect attempt', delay);
this.reconnecting = true;
View
10 test/connection.js
@@ -54,6 +54,16 @@ describe('connection', function() {
});
});
+ it('should call user\'s backoff function when given', function() {
+ var called = false;
+ socket.io.reconnectionBackoffMethod(function(){
+ called = true;
+ return 100;
+ });
+ socket.io.reconnect();
+ expect(called).to.be(true);
+ });
+
it('should try to reconnect twice and fail when requested two attempts with incorrect address and reconnect enabled', function(done) {
var manager = io.Manager('http://localhost:3940', { reconnection: true, reconnectionAttempts: 2, reconnectionDelay: 10 });
var socket = manager.socket('/asd');
Something went wrong with that request. Please try again.