commit 6d289797bf1c941c57b72adeca01f0a4fd364bc9
parent bad983389639cc923b622cde546e57d842e1db98
Author: Dan Stillman <dstillman@zotero.org>
Date: Thu, 12 Nov 2015 02:40:01 -0500
Retry API requests automatically after 5xx errors
Diffstat:
2 files changed, 44 insertions(+), 14 deletions(-)
diff --git a/chrome/content/zotero/xpcom/http.js b/chrome/content/zotero/xpcom/http.js
@@ -36,6 +36,9 @@ Zotero.HTTP = new function() {
this.UnexpectedStatusException.prototype.is4xx = function () {
return this.status >= 400 && this.status < 500;
}
+ this.UnexpectedStatusException.prototype.is5xx = function () {
+ return this.status >= 500 && this.status < 600;
+ }
this.UnexpectedStatusException.prototype.toString = function() {
return this.message;
};
diff --git a/chrome/content/zotero/xpcom/sync/syncAPIClient.js b/chrome/content/zotero/xpcom/sync/syncAPIClient.js
@@ -37,6 +37,8 @@ Zotero.Sync.APIClient = function (options) {
this.apiVersion = options.apiVersion;
this.apiKey = options.apiKey;
this.caller = options.caller;
+
+ this.failureDelayIntervals = [2500, 5000, 10000, 20000, 40000, 60000, 120000, 240000, 300000];
}
Zotero.Sync.APIClient.prototype = {
@@ -437,25 +439,50 @@ Zotero.Sync.APIClient.prototype = {
},
- makeRequest: function (method, uri, options = {}) {
+ makeRequest: Zotero.Promise.coroutine(function* (method, uri, options = {}) {
options.headers = this.getHeaders(options.headers);
options.dontCache = true;
options.foreground = !options.background;
options.responseType = options.responseType || 'text';
- return this.caller.start(Zotero.Promise.coroutine(function* () {
- try {
- var xmlhttp = yield Zotero.HTTP.request(method, uri, options);
- this._checkBackoff(xmlhttp);
- return xmlhttp;
- }
- catch (e) {
- /*if (e instanceof Zotero.HTTP.UnexpectedStatusException) {
- this._checkRetry(e.xmlhttp);
- }*/
- throw e;
+ var tries = 0;
+ var failureDelayGenerator = null;
+ while (true) {
+ var result = yield this.caller.start(Zotero.Promise.coroutine(function* () {
+ try {
+ var xmlhttp = yield Zotero.HTTP.request(method, uri, options);
+ this._checkBackoff(xmlhttp);
+ return xmlhttp;
+ }
+ catch (e) {
+ tries++;
+ if (e instanceof Zotero.HTTP.UnexpectedStatusException) {
+ //this._checkRetry(e.xmlhttp);
+
+ if (e.is5xx()) {
+ Zotero.logError(e);
+ if (!failureDelayGenerator) {
+ // Keep trying for up to an hour
+ failureDelayGenerator = Zotero.Utilities.Internal.delayGenerator(
+ this.failureDelayIntervals, 60 * 60 * 1000
+ );
+ }
+ let keepGoing = yield failureDelayGenerator.next();
+ if (!keepGoing) {
+ Zotero.logError("Failed too many times");
+ throw lastError;
+ }
+ return false;
+ }
+ }
+ throw e;
+ }
+ }.bind(this)));
+
+ if (result) {
+ return result;
}
- }.bind(this)));
- },
+ }
+ }),
_parseJSON: function (json) {