Author: ddumont
Date: Mon Jun 18 19:59:29 2012
New Revision: 1351468
URL: http://svn.apache.org/viewvc?rev=1351468&view=rev
Log:
SHINDIG-1805 - Better error handling around container token refreshes.
Modified:
shindig/trunk/features/src/main/javascript/features/container.util/constant.js
shindig/trunk/features/src/main/javascript/features/container/container.js
shindig/trunk/features/src/main/javascript/features/container/service.js
Modified:
shindig/trunk/features/src/main/javascript/features/container.util/constant.js
URL:
http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/container.util/constant.js?rev=1351468&r1=1351467&r2=1351468&view=diff
==============================================================================
---
shindig/trunk/features/src/main/javascript/features/container.util/constant.js
(original)
+++
shindig/trunk/features/src/main/javascript/features/container.util/constant.js
Mon Jun 18 19:59:29 2012
@@ -332,7 +332,14 @@ osapi.container.ContainerConfig = {
* var token, ttl, error = false;
* // Do work to set token and ttl values
* if (error) {
- * result();
+ * var undef;
+ * if (error.isFatal()) {
+ * // Run all callbacks and let them know there was a horrible
error.
+ * // The container token is not valid, and probably won't be any
time soon.
+ * result(undef, 30, 'There was an error!'); // Try again for a
miracle in 30 seconds.
+ * } else {
+ * result(undef, 15); // Call me again in 15 seconds, please
+ * }
* } else {
* result(token, ttl);
* }
Modified:
shindig/trunk/features/src/main/javascript/features/container/container.js
URL:
http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/container/container.js?rev=1351468&r1=1351467&r2=1351468&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/container/container.js
(original)
+++ shindig/trunk/features/src/main/javascript/features/container/container.js
Mon Jun 18 19:59:29 2012
@@ -519,8 +519,11 @@ osapi.container.Container.prototype.getS
* unless the token is specified in the optional parameter, in which case the
token will be
* updated with the provided value immediately.
*
- * @param {function=} callback Function to run when container token is valid.
- * @param {String=} token The containers new security token.
+ * @param {function(error)=} callback Function to run when refresh completes
or is cancelled.
+ * error will be undefined if there is no error.
+ * @param {String=|boolean} tokenOrWait
+ * token The container's new security token.
+ * wait If the callback should not trigger a token fetch.
* @param {number=} ttl The token's ttl in seconds. If token is specified and
ttl is 0,
* token refresh will be disabled.
* @see osapi.container.ContainerConfig.GET_CONTAINER_TOKEN (constants.js)
@@ -539,14 +542,20 @@ osapi.container.Container.prototype.sche
oldInterval = this.tokenRefreshInterval_,
newInterval = tokenTTL ? this.setRefreshTokenInterval_(tokenTTL * 1000)
: oldInterval,
refresh = function() {
- self.updateContainerSecurityToken(function() {
- self.lastRefresh_ = osapi.container.util.getCurrentTimeMs();
- // Schedule the next refresh.
- self.tokenRefreshTimer_ = setTimeout(refresh, newInterval);
-
- // Do this last so that if it ever errors, we maintain the refresh
schedule.
- self.refreshTokens_();
- });
+ function callback(error) {
+ if (error) {
+ // try again, but don't force a refresh.
+ setTimeout(gadgets.util.makeClosure(self,
self.updateContainerSecurityToken, callback, true), 1);
+ } else {
+ self.lastRefresh_ = osapi.container.util.getCurrentTimeMs();
+ // Schedule the next refresh.
+ self.tokenRefreshTimer_ = setTimeout(refresh, newInterval);
+
+ // Do this last so that if it ever errors, we maintain the refresh
schedule.
+ self.refreshTokens_();
+ }
+ }
+ self.updateContainerSecurityToken(callback);
};
// If enabled, check to see if we no schedule or if the two intervals are
different and update the schedule.
Modified:
shindig/trunk/features/src/main/javascript/features/container/service.js
URL:
http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/container/service.js?rev=1351468&r1=1351467&r2=1351468&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/container/service.js
(original)
+++ shindig/trunk/features/src/main/javascript/features/container/service.js
Mon Jun 18 19:59:29 2012
@@ -125,28 +125,36 @@ osapi.container.Service.prototype.getGad
request['ids'] = uncachedUrls;
request['language'] = this.getLanguage();
request['country'] = this.getCountry();
- this.updateContainerSecurityToken(function() {
- osapi['gadgets']['metadata'](request).execute(function(response) {
- // If response entirely fails, augment individual errors.
- if (response['error']) {
- for (var i = 0; i < request['ids'].length; i++) {
- var id = request['ids'][i];
- finalResponse[id] = { 'error' : response['error'] };
- }
-
- // Otherwise, cache response. Augment final response with server
response.
- } else {
- var currentTimeMs = osapi.container.util.getCurrentTimeMs();
- for (var id in response) {
- var resp = response[id];
- self.updateResponse_(resp, id, currentTimeMs);
- self.cachedMetadatas_[id] = resp;
- finalResponse[id] = resp;
- }
+ this.updateContainerSecurityToken(function(error) {
+ if (error) {
+ for (var i = 0; i < request['ids'].length; i++) {
+ var id = request['ids'][i];
+ finalResponse[id] = { 'error' : error };
}
-
callback(finalResponse);
- });
+ } else {
+ osapi['gadgets']['metadata'](request).execute(function(response) {
+ // If response entirely fails, augment individual errors.
+ if (response['error']) {
+ for (var i = 0; i < request['ids'].length; i++) {
+ var id = request['ids'][i];
+ finalResponse[id] = { 'error' : response['error'] };
+ }
+
+ // Otherwise, cache response. Augment final response with server
response.
+ } else {
+ var currentTimeMs = osapi.container.util.getCurrentTimeMs();
+ for (var id in response) {
+ var resp = response[id];
+ self.updateResponse_(resp, id, currentTimeMs);
+ self.cachedMetadatas_[id] = resp;
+ finalResponse[id] = resp;
+ }
+ }
+
+ callback(finalResponse);
+ });
+ }
});
}
};
@@ -243,11 +251,15 @@ osapi.container.Service.prototype.getGad
};
// If we have a custom token fetch function, call it -- otherwise use the
default
- self.updateContainerSecurityToken(function() {
- if (self.config_[osapi.container.ContainerConfig.GET_GADGET_TOKEN]) {
- self.config_[osapi.container.ContainerConfig.GET_GADGET_TOKEN](request,
tokenResponseCallback);
+ self.updateContainerSecurityToken(function(error) {
+ if (error) {
+ tokenResponseCallback({'error': error});
} else {
- osapi['gadgets']['token'](request).execute(tokenResponseCallback);
+ if (self.config_[osapi.container.ContainerConfig.GET_GADGET_TOKEN]) {
+
self.config_[osapi.container.ContainerConfig.GET_GADGET_TOKEN](request,
tokenResponseCallback);
+ } else {
+ osapi['gadgets']['token'](request).execute(tokenResponseCallback);
+ }
}
});
};
@@ -410,14 +422,14 @@ osapi.container.Service.prototype.getCou
callbacks = [];
- function runCallbacks(callbacks) {
+ function runCallbacks(callbacks, error) {
while (callbacks.length) {
- callbacks.shift().call(null); // Window context
+ callbacks.shift().call(null, error); // Window context
}
}
function refresh(fetch_once) {
- fetching = true;
+ var self = this;
if (containerTimeout) {
clearTimeout(containerTimeout);
containerTimeout = 0;
@@ -425,26 +437,30 @@ osapi.container.Service.prototype.getCou
var fetch = fetch_once ||
this.config_[osapi.container.ContainerConfig.GET_CONTAINER_TOKEN];
if (fetch) {
- var self = this;
- fetch(function(token, ttl) { // token and ttl may be undefined in the
case of an error
- fetching = false;
-
- // Use last known ttl if there was an error
- containerTokenTTL = token ? (ttl * 1000 * 0.8) : containerTokenTTL;
- if (containerTokenTTL) {
- // Refresh again in 80% of the reported ttl
- // Pass null in to closure because FF behaves un-expectedly when
that param is not explicitly provided.
- containerTimeout = setTimeout(gadgets.util.makeClosure(self,
refresh, null), containerTokenTTL);
- }
+ if (!fetching) {
+ fetching = true;
+ fetch(function(token, ttl, error) { // token and ttl may be undefined
in the case of an error
+ fetching = false;
+
+ // Use last known ttl if there was an error
+ containerTokenTTL = typeof(ttl) == 'number' ? (ttl * 1000 * 0.8) :
containerTokenTTL;
+ if (containerTokenTTL) {
+ // Refresh again in 80% of the reported ttl
+ // Pass null in to closure because FF behaves un-expectedly when
that param is not explicitly provided.
+ containerTimeout = setTimeout(gadgets.util.makeClosure(self,
refresh, null), containerTokenTTL);
+ }
- if (token) {
- // Looks like everything worked out... let's update the token.
- shindig.auth.updateSecurityToken(token);
- lastRefresh = osapi.container.util.getCurrentTimeMs();
- // And then run all the callbacks waiting for this.
- runCallbacks(callbacks);
- }
- });
+ if (token) {
+ // Looks like everything worked out... let's update the token.
+ shindig.auth.updateSecurityToken(token);
+ lastRefresh = osapi.container.util.getCurrentTimeMs();
+ // And then run all the callbacks waiting for this.
+ runCallbacks(callbacks);
+ } else if (error) {
+ runCallbacks(callbacks, error);
+ }
+ });
+ }
} else {
fetching = false;
// Fail gracefully, container supplied no fetch function. Do not hold on
to callbacks.
@@ -455,8 +471,11 @@ osapi.container.Service.prototype.getCou
/**
* @see osapi.container.Container.prototype.updateContainerSecurityToken
*/
- osapi.container.Service.prototype.updateContainerSecurityToken =
function(callback, token, ttl) {
- var now = osapi.container.util.getCurrentTimeMs(),
+ osapi.container.Service.prototype.updateContainerSecurityToken =
function(callback, tokenOrWait, ttl) {
+ var undef,
+ now = osapi.container.util.getCurrentTimeMs(),
+ token = typeof(tokenOrWait) != 'boolean' && tokenOrWait || undef,
+ wait = typeof(tokenOrWait) == 'boolean' && tokenOrWait,
needsRefresh = containerTokenTTL &&
(fetching || token || !lastRefresh || now > lastRefresh +
containerTokenTTL);
if (needsRefresh) {
@@ -478,8 +497,14 @@ osapi.container.Service.prototype.getCou
refresh.call(this, function(result) {
result(token, ttl);
});
- } else if (!fetching) {
- // There's no fetch going on right now. We need to start one because
the token needs a refresh
+ } else if (!fetching && !wait) {
+ // There's no fetch going on right now. Unless wait is true, we need
to start one right away
+ // because the token needs a refresh.
+
+ // If wait is true, the callback really just wants a valid token. It
may be called with an
+ // error for informational purposes, but it's likely the callback will
simply queue up
+ // immediately if there was an error. To avoid spamming the refresh
method, we allow them to
+ // specify `wait` so that it can wait for success without forcing a
fetch.
refresh.call(this);
}
} else if (callback) {