Reload the client on DDP version negotiation failure

on the default connection, on the assumption that new
client code will be able to negotiate successfully.

Uses an exponential backoff if after reload the DDP version
negotiation fails again.
This commit is contained in:
Andrew Wilcox
2013-11-08 12:55:01 -05:00
committed by Nick Martin
parent a741726dfc
commit cbc28e1c7f
3 changed files with 42 additions and 9 deletions

View File

@@ -11,8 +11,38 @@ if (Meteor.isClient) {
if (__meteor_runtime_config__.DDP_DEFAULT_CONNECTION_URL)
ddpUrl = __meteor_runtime_config__.DDP_DEFAULT_CONNECTION_URL;
}
var negotiationFailuresKey = "Meteor.DDPVersionNegotiationFailures";
var onConnected = function () {
Meteor._localStorage.removeItem(negotiationFailuresKey);
};
var exponentialBackoff = function (failures) {
return Math.pow(failures, 1.5) * 1000;
};
var onDDPVersionNegotiationFailure = function (serverRequestedVersion) {
if (Package.reload) {
var failures = parseInt(Meteor._localStorage.getItem(negotiationFailuresKey) || "0") + 1;
Meteor._localStorage.setItem(negotiationFailuresKey, "" + failures);
Meteor.setTimeout(
function () {
Package.reload.Reload._reload();
},
exponentialBackoff(failures)
);
}
else {
Meteor._debug("DDP version negotiation failed; server requested version " + serverRequestedVersion);
}
};
Meteor.connection =
DDP.connect(ddpUrl, true /* restart_on_update */);
DDP.connect(ddpUrl, {
onConnected: onConnected,
onDDPVersionNegotiationFailure: onDDPVersionNegotiationFailure
});
// Proxy the public methods of Meteor.connection so they can
// be called directly on Meteor.

View File

@@ -8,16 +8,17 @@ if (Meteor.isServer) {
// or an object as a test hook (see code)
// Options:
// reloadWithOutstanding: is it OK to reload if there are outstanding methods?
// onDDPNegotiationVersionFailure: callback with the server requested version.
var Connection = function (url, options) {
var self = this;
options = _.extend({
onConnected: function () {},
onDDPVersionNegotiationFailure: function (serverRequestedVersion, error) {
Meteor._debug("Failed DDP connection: " + error);
},
// These options are only for testing.
reloadWithOutstanding: false,
supportedDDPVersions: SUPPORTED_DDP_VERSIONS,
onConnectionFailure: function (reason) {
Meteor._debug("Failed DDP connection: " + reason);
},
onConnected: function () {}
supportedDDPVersions: SUPPORTED_DDP_VERSIONS
}, options);
// If set, called when we reconnect, queuing method calls _before_ the
@@ -197,7 +198,7 @@ var Connection = function (url, options) {
var error =
"Version negotiation failed; server requested version " + msg.version;
self._stream.disconnect({_permanent: true, _error: error});
options.onConnectionFailure(error);
options.onDDPVersionNegotiationFailure(msg.version, error);
}
}
else if (_.include(['added', 'changed', 'removed', 'ready', 'updated'], msg.msg))
@@ -1378,8 +1379,8 @@ LivedataTest.Connection = Connection;
// "/",
// "ddp+sockjs://ddp--****-foo.meteor.com/sockjs"
//
DDP.connect = function (url) {
var ret = new Connection(url);
DDP.connect = function (url, options) {
var ret = new Connection(url, options);
allConnections.push(ret); // hack. see below.
return ret;
};

View File

@@ -25,6 +25,8 @@ Package.on_use(function (api) {
// If the facts package is loaded, publish some statistics.
api.use('facts', 'server', {weak: true});
api.use('localstorage', 'client');
api.export('DDP');
api.export('DDPServer', 'server');