Skip to content

Instantly share code, notes, and snippets.

@Frenchcooc
Last active July 27, 2020 07:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Frenchcooc/7c042b4e0467d592c703dc822178449e to your computer and use it in GitHub Desktop.
Save Frenchcooc/7c042b4e0467d592c703dc822178449e to your computer and use it in GitHub Desktop.
Handling retries client-side for Google Apps Script add-ons
// Handle retries when calling Apps Script functions,
// from the client-side (i.e. a browser).
//
// @usage:
// - google.script.run.withRetry().myFunction() // Will retry "myFunction" 2 times
// - google.script.run.withRetry(5).myFunction() // Will retry "myFunction" 5 times
//
// /!\ Known caveats. The method withUserObject(object) is not supported.
if (google && google.script && google.script.run) {
google.script.run.withRetry = function (maxRetries) {
return new (function () {
this._successHandler = null;
this._failureHandler = null;
this.withSuccessHandler = function (callback) {
this._successHandler = callback;
return this;
};
this.withFailureHandler = function (callback) {
this._failureHandler = callback;
return this;
};
function _runWithRetry(backendFunction, nRetries, successHandler, failureHandler, _arguments) {
let _run = google.script.run;
let _totalRetries = isNaN(nRetries) ? 0 : nRetries;
let _maxRetries = typeof maxRetries === "number" ? maxRetries : 2;
if (!_run[backendFunction]) {
throw new Error(backendFunction + " is not defined");
}
if (successHandler) {
_run = _run.withSuccessHandler(successHandler);
}
_run = _run.withFailureHandler(function (err) {
if (_totalRetries < _maxRetries) {
return _runWithRetry(backendFunction, _totalRetries + 1, successHandler, failureHandler, _arguments);
}
if (failureHandler) {
return failureHandler(err);
}
});
const _maximumBackoff = 32 * 1000;
const _randomMilliseconds = Math.round(Math.random() * 1000);
const _backoffTime = Math.min(Math.pow(2, _totalRetries - 2) * 1000 + _randomMilliseconds, _maximumBackoff);
const _executionDelay = _totalRetries > 0 ? _backoffTime : 0;
window.setTimeout(function () {
_run[backendFunction].apply(null, _arguments);
}, _executionDelay);
}
this._run = function () {
_runWithRetry(this._backendFunction, 0, this._successHandler, this._failureHandler, arguments);
};
const _backendFunctions = [];
for (let key in google.script.run) {
if (key.indexOf("with") === 0) {
continue;
}
_backendFunctions.push(key);
}
for (let i = 0; i < _backendFunctions.length; i++) {
const functionName = _backendFunctions[i];
this[functionName] = new Function(
'this._backendFunction = "' + functionName + '"; this._run.apply(this, arguments)'
);
}
})();
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment