From cbc28e1c7ff70db19a73c162ead567629608f73a Mon Sep 17 00:00:00 2001 From: Andrew Wilcox Date: Fri, 8 Nov 2013 12:55:01 -0500 Subject: [PATCH] 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. --- packages/livedata/client_convenience.js | 32 +++++++++++++++++++++++- packages/livedata/livedata_connection.js | 17 +++++++------ packages/livedata/package.js | 2 ++ 3 files changed, 42 insertions(+), 9 deletions(-) diff --git a/packages/livedata/client_convenience.js b/packages/livedata/client_convenience.js index b6992d1ac7..5838ab1e2d 100644 --- a/packages/livedata/client_convenience.js +++ b/packages/livedata/client_convenience.js @@ -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. diff --git a/packages/livedata/livedata_connection.js b/packages/livedata/livedata_connection.js index f71db523bc..fd62c5c5a1 100644 --- a/packages/livedata/livedata_connection.js +++ b/packages/livedata/livedata_connection.js @@ -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; }; diff --git a/packages/livedata/package.js b/packages/livedata/package.js index f0f7a7e5b2..d8c01f2cab 100644 --- a/packages/livedata/package.js +++ b/packages/livedata/package.js @@ -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');