Upgrading socket.io, widening reconnection delay.

This commit is contained in:
Samuel Clay 2013-03-15 12:11:29 -07:00
parent 16db855454
commit 0b81276c90
5 changed files with 158 additions and 61 deletions

View file

@ -44,6 +44,8 @@ backend node
server node13 192.34.61.227:8888 check inter 500ms
server node14 198.211.109.155:8888 check inter 500ms
server node15 198.211.107.87:8888 check inter 500ms
server node16 198.211.105.155:8888 check inter 500ms
server node17 198.211.104.133:8888 check inter 500ms
backend nginx
balance roundrobin
@ -59,6 +61,9 @@ backend nginx
server nginx13 192.34.61.227:80 check inter 500ms
server nginx14 198.211.109.155:80 check inter 500ms
server nginx15 198.211.107.87:80 check inter 500ms
server nginx16 198.211.105.155:8888 check inter 500ms
server nginx17 198.211.104.133:8888 check inter 500ms
frontend stats
bind :1936 ssl crt newsblur.pem

View file

@ -12,6 +12,8 @@
192.34.61.227 app13 app13.newsblur.com
198.211.109.155 app14 app14.newsblur.com
198.211.107.87 app15 app15.newsblur.com
198.211.105.155 app16 app16.newsblur.com
198.211.104.133 app17 app17.newsblur.com
199.15.249.101 db01 db01.newsblur.com
199.15.252.50 db02 db02.newsblur.com

4
fabfile.py vendored
View file

@ -42,6 +42,8 @@ env.roledefs ={
'192.34.61.227',
'198.211.109.155',
'198.211.107.87',
'198.211.105.155',
'198.211.104.133',
],
'dev': ['dev.newsblur.com'],
'web': ['app01.newsblur.com',
@ -98,6 +100,8 @@ env.roledefs ={
'198.211.109.155',
'198.211.109.197',
'198.211.107.87',
'198.211.105.155',
'198.211.104.133',
]
}

View file

@ -3860,7 +3860,9 @@
var port = _.string.startsWith(window.location.protocol, 'https') ? 8889 : 8888;
var server = window.location.protocol + '//' + window.location.hostname;
if (NEWSBLUR.Globals.debug) server = server + ':' + port;
this.socket = this.socket || io.connect(server);
this.socket = this.socket || io.connect(server, {
"reconnection delay": 10000
});
// this.socket.refresh_feeds = _.debounce(_.bind(this.force_feeds_refresh, this), 1000*10);
this.socket.on('connect', _.bind(function() {

View file

@ -1,4 +1,7 @@
/*! Socket.IO.js build:0.9.4, development. Copyright(c) 2011 LearnBoost <dev@learnboost.com> MIT Licensed */
/*! Socket.IO.js build:0.9.11, development. Copyright(c) 2011 LearnBoost <dev@learnboost.com> MIT Licensed */
var io = ('undefined' === typeof module ? {} : module.exports);
(function() {
/**
* socket.io
@ -22,7 +25,7 @@
* @api public
*/
io.version = '0.9.4';
io.version = '0.9.11';
/**
* Protocol implemented.
@ -259,7 +262,7 @@
util.request = function (xdomain) {
if (xdomain && 'undefined' != typeof XDomainRequest) {
if (xdomain && 'undefined' != typeof XDomainRequest && !util.ua.hasCORS) {
return new XDomainRequest();
}
@ -315,7 +318,7 @@
*
* @api public
*/
util.merge = function merge (target, additional, deep, lastseen) {
var seen = lastseen || []
, depth = typeof deep == 'undefined' ? 2 : deep
@ -340,7 +343,7 @@
*
* @api public
*/
util.mixin = function (ctor, ctor2) {
util.merge(ctor.prototype, ctor2.prototype);
};
@ -388,7 +391,7 @@
}
return ret;
}
};
/**
* Array indexOf compatibility.
@ -398,8 +401,8 @@
*/
util.indexOf = function (arr, o, i) {
for (var j = arr.length, i = i < 0 ? i + j < 0 ? 0 : i + j : i || 0;
for (var j = arr.length, i = i < 0 ? i + j < 0 ? 0 : i + j : i || 0;
i < j && arr[i] !== o; i++) {}
return j <= i ? -1 : i;
@ -453,8 +456,16 @@
util.ua.webkit = 'undefined' != typeof navigator
&& /webkit/i.test(navigator.userAgent);
})('undefined' != typeof io ? io : module.exports, this);
/**
* Detect iPad/iPhone/iPod.
*
* @api public
*/
util.ua.iDevice = 'undefined' != typeof navigator
&& /iPad|iPhone|iPod/i.test(navigator.userAgent);
})('undefined' != typeof io ? io : module.exports, this);
/**
* socket.io
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
@ -565,11 +576,10 @@
*/
EventEmitter.prototype.removeAllListeners = function (name) {
// TODO: enable this when node 0.5 is stable
//if (name === undefined) {
//this.$events = {};
//return this;
//}
if (name === undefined) {
this.$events = {};
return this;
}
if (this.$events && this.$events[name]) {
this.$events[name] = null;
@ -657,7 +667,7 @@
return exports.JSON = {
parse: nativeJSON.parse
, stringify: nativeJSON.stringify
}
};
}
var JSON = exports.JSON = {};
@ -1254,6 +1264,17 @@
io.util.mixin(Transport, io.EventEmitter);
/**
* Indicates whether heartbeats is enabled for this transport
*
* @api private
*/
Transport.prototype.heartbeats = function () {
return true;
};
/**
* Handles the response from the server. When a new response is received
* it will automatically update the timeout, decode the message and
@ -1265,8 +1286,8 @@
Transport.prototype.onData = function (data) {
this.clearCloseTimeout();
// If the connection in currently open (or in a reopening state) reset the close
// If the connection in currently open (or in a reopening state) reset the close
// timeout since we have just received data. This check is necessary so
// that we don't reset the timeout on an explicitly disconnected connection.
if (this.socket.connected || this.socket.connecting || this.socket.reconnecting) {
@ -1305,7 +1326,7 @@
}
if (packet.type == 'error' && packet.advice == 'reconnect') {
this.open = false;
this.isOpen = false;
}
this.socket.onPacket(packet);
@ -1318,7 +1339,7 @@
*
* @api private
*/
Transport.prototype.setCloseTimeout = function () {
if (!this.closeTimeout) {
var self = this;
@ -1336,7 +1357,7 @@
*/
Transport.prototype.onDisconnect = function () {
if (this.close && this.open) this.close();
if (this.isOpen) this.close();
this.clearTimeouts();
this.socket.onDisconnect();
return this;
@ -1351,7 +1372,7 @@
Transport.prototype.onConnect = function () {
this.socket.onConnect();
return this;
}
};
/**
* Clears close timeout
@ -1402,7 +1423,7 @@
Transport.prototype.onHeartbeat = function (heartbeat) {
this.packet({ type: 'heartbeat' });
};
/**
* Called when the transport opens.
*
@ -1410,7 +1431,7 @@
*/
Transport.prototype.onOpen = function () {
this.open = true;
this.isOpen = true;
this.clearCloseTimeout();
this.socket.onOpen();
};
@ -1430,7 +1451,7 @@
self.open();
}, this.socket.options['reopen delay']);*/
this.open = false;
this.isOpen = false;
this.socket.onClose();
this.onDisconnect();
};
@ -1502,9 +1523,10 @@
, 'reconnection limit': Infinity
, 'reopen delay': 3000
, 'max reconnection attempts': 10
, 'sync disconnect on unload': true
, 'sync disconnect on unload': false
, 'auto connect': true
, 'flash policy port': 10843
, 'manualFlush': false
};
io.util.merge(this.options, options);
@ -1520,8 +1542,7 @@
if (this.options['sync disconnect on unload'] &&
(!this.isXDomain() || io.util.ua.hasCORS)) {
var self = this;
io.util.on(global, 'unload', function () {
io.util.on(global, 'beforeunload', function () {
self.disconnectSync();
}, false);
}
@ -1588,6 +1609,7 @@
function complete (data) {
if (data instanceof Error) {
self.connecting = false;
self.onError(data.message);
} else {
fn.apply(null, data.split(':'));
@ -1617,14 +1639,19 @@
var xhr = io.util.request();
xhr.open('GET', url, true);
xhr.withCredentials = true;
if (this.isXDomain()) {
xhr.withCredentials = true;
}
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
xhr.onreadystatechange = empty;
if (xhr.status == 200) {
complete(xhr.responseText);
} else if (xhr.status == 403) {
self.onError(xhr.responseText);
} else {
self.connecting = false;
!self.reconnecting && self.onError(xhr.responseText);
}
}
@ -1645,7 +1672,7 @@
for (var i = 0, transport; transport = transports[i]; i++) {
if (io.Transport[transport]
&& io.Transport[transport].check(this)
&& (!this.isXDomain() || io.Transport[transport].xdomainCheck())) {
&& (!this.isXDomain() || io.Transport[transport].xdomainCheck(this))) {
return new io.Transport[transport](this, this.sessionid);
}
}
@ -1667,15 +1694,17 @@
}
var self = this;
self.connecting = true;
this.handshake(function (sid, heartbeat, close, transports) {
self.sessionid = sid;
self.closeTimeout = close * 1000;
self.heartbeatTimeout = heartbeat * 1000;
self.transports = transports ? io.util.intersect(
transports.split(',')
, self.options.transports
) : self.options.transports;
if(!self.transports)
self.transports = self.origTransports = (transports ? io.util.intersect(
transports.split(',')
, self.options.transports
) : self.options.transports);
self.setHeartbeatTimeout();
@ -1697,11 +1726,7 @@
self.connecting = false;
if (self.options['try multiple transports']) {
if (!self.remainingTransports) {
self.remainingTransports = self.transports.slice(0);
}
var remaining = self.remainingTransports;
var remaining = self.transports;
while (remaining.length > 0 && remaining.splice(0,1)[0] !=
self.transport.name) {}
@ -1739,6 +1764,7 @@
Socket.prototype.setHeartbeatTimeout = function () {
clearTimeout(this.heartbeatTimeoutTimer);
if(this.transport && !this.transport.heartbeats()) return;
var self = this;
this.heartbeatTimeoutTimer = setTimeout(function () {
@ -1774,11 +1800,25 @@
this.doBuffer = v;
if (!v && this.connected && this.buffer.length) {
this.transport.payload(this.buffer);
this.buffer = [];
if (!this.options['manualFlush']) {
this.flushBuffer();
}
}
};
/**
* Flushes the buffer data over the wire.
* To be invoked manually when 'manualFlush' is set to true.
*
* @api public
*/
Socket.prototype.flushBuffer = function() {
this.transport.payload(this.buffer);
this.buffer = [];
};
/**
* Disconnect the established connect.
*
@ -1807,10 +1847,18 @@
Socket.prototype.disconnectSync = function () {
// ensure disconnection
var xhr = io.util.request()
, uri = this.resource + '/' + io.protocol + '/' + this.sessionid;
var xhr = io.util.request();
var uri = [
'http' + (this.options.secure ? 's' : '') + ':/'
, this.options.host + ':' + this.options.port
, this.options.resource
, io.protocol
, ''
, this.sessionid
].join('/') + '/?disconnect=1';
xhr.open('GET', uri, true);
xhr.open('GET', uri, false);
xhr.send(null);
// handle disconnection immediately
this.onDisconnect('booted');
@ -1986,6 +2034,7 @@
if (!self.redoTransports) {
self.on('connect_failed', maybeReconnect);
self.options['try multiple transports'] = true;
self.transports = self.origTransports;
self.transport = self.getTransport();
self.redoTransports = true;
self.connect();
@ -2347,10 +2396,23 @@
* @api public
*/
WS.prototype.send = function (data) {
this.websocket.send(data);
return this;
};
// Do to a bug in the current IDevices browser, we need to wrap the send in a
// setTimeout, when they resume from sleeping the browser will crash if
// we don't allow the browser time to detect the socket has been closed
if (io.util.ua.iDevice) {
WS.prototype.send = function (data) {
var self = this;
setTimeout(function() {
self.websocket.send(data);
},0);
return this;
};
} else {
WS.prototype.send = function (data) {
this.websocket.send(data);
return this;
};
}
/**
* Payload
@ -3173,7 +3235,7 @@ var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="Sho
var request = io.util.request(xdomain),
usesXDomReq = (global.XDomainRequest && request instanceof XDomainRequest),
socketProtocol = (socket && socket.options && socket.options.secure ? 'https:' : 'http:'),
isXProtocol = (socketProtocol != global.location.protocol);
isXProtocol = (global.location && socketProtocol != global.location.protocol);
if (request && !(usesXDomReq && isXProtocol)) {
return true;
}
@ -3189,8 +3251,8 @@ var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="Sho
* @api public
*/
XHR.xdomainCheck = function () {
return XHR.check(null, true);
XHR.xdomainCheck = function (socket) {
return XHR.check(socket, true);
};
})(
@ -3334,11 +3396,11 @@ var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="Sho
* @api public
*/
HTMLFile.check = function () {
HTMLFile.check = function (socket) {
if (typeof window != "undefined" && (['Active'].concat('Object').join('X')) in window){
try {
var a = new window[(['Active'].concat('Object').join('X'))]('htmlfile');
return a && io.Transport.XHR.check();
return a && io.Transport.XHR.check(socket);
} catch(e){}
}
return false;
@ -3416,6 +3478,16 @@ var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="Sho
XHRPolling.prototype.name = 'xhr-polling';
/**
* Indicates whether heartbeats is enabled for this transport
*
* @api private
*/
XHRPolling.prototype.heartbeats = function () {
return false;
};
/**
* Establish a connection, for iPhone and Android this will be done once the page
* is loaded.
@ -3440,7 +3512,7 @@ var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="Sho
function empty () {};
XHRPolling.prototype.get = function () {
if (!this.open) return;
if (!this.isOpen) return;
var self = this;
@ -3460,12 +3532,18 @@ var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="Sho
function onload () {
this.onload = empty;
this.onerror = empty;
self.retryCounter = 1;
self.onData(this.responseText);
self.get();
};
function onerror () {
self.onClose();
self.retryCounter ++;
if(!self.retryCounter || self.retryCounter > 3) {
self.onClose();
} else {
self.get();
}
};
this.xhr = this.request();
@ -3617,8 +3695,9 @@ var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="Sho
form.className = 'socketio';
form.style.position = 'absolute';
form.style.top = '-1000px';
form.style.left = '-1000px';
form.style.top = '0px';
form.style.left = '0px';
form.style.display = 'none';
form.target = id;
form.method = 'POST';
form.setAttribute('accept-charset', 'utf-8');
@ -3678,7 +3757,7 @@ var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="Sho
this.socket.setBuffer(true);
};
/**
* Creates a new JSONP poll that can be used to listen
* for messages from the Socket.IO server.
@ -3705,7 +3784,7 @@ var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="Sho
self.onClose();
};
var insertAt = document.getElementsByTagName('script')[0]
var insertAt = document.getElementsByTagName('script')[0];
insertAt.parentNode.insertBefore(script, insertAt);
this.script = script;
@ -3727,7 +3806,7 @@ var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="Sho
JSONPPolling.prototype._ = function (msg) {
this.onData(msg);
if (this.open) {
if (this.isOpen) {
this.get();
}
return this;
@ -3785,3 +3864,8 @@ var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="Sho
, 'undefined' != typeof io ? io : module.parent.exports
, this
);
if (typeof define === "function" && define.amd) {
define([], function () { return io; });
}
})();