@scriptaddicts/gas-error-handler
Advanced tools
+1
-1
| { | ||
| "name": "@scriptaddicts/gas-error-handler", | ||
| "version": "1.0.1", | ||
| "version": "1.1.0", | ||
| "description": "Methods to handle error in GAS", | ||
@@ -5,0 +5,0 @@ "author": { |
+109
-42
@@ -9,2 +9,3 @@ /**************************************************************** | ||
| * expBackoff() | ||
| * urlFetchWithExpBackOff() | ||
| * logError() | ||
@@ -36,51 +37,98 @@ * | ||
| function expBackoff(func) { | ||
| // execute func() then retry 5 times at most if errors | ||
| for (var n = 0; n < 6; n++) { | ||
| try { | ||
| return func(); | ||
| // actual exponential backoff | ||
| n && Utilities.sleep((Math.pow(2, n-1) * 1000) + (Math.round(Math.random() * 1000))); | ||
| var response = undefined; | ||
| var error = undefined; | ||
| var noError = true; | ||
| var isUrlFetchResponse = false; | ||
| // Try / catch func() | ||
| try { response = func() } | ||
| catch(err) { | ||
| error = err; | ||
| noError = false; | ||
| } | ||
| catch(e) { | ||
| if (e.message) { | ||
| // Check for errors thrown by Google APIs on which there's no need to retry | ||
| // eg: "Access denied by a security policy established by the administrator of your organization. | ||
| // Please contact your administrator for further assistance." | ||
| if (e.message.indexOf('Invalid requests') !== -1 | ||
| || e.message.indexOf('Access denied') !== -1 | ||
| || e.message.indexOf('Mail service not enabled') !== -1) { | ||
| throw e; | ||
| } | ||
| // TODO: YAMM specific ?: move to YAMM code | ||
| else if (e.message.indexOf('response too large') !== -1) { | ||
| // Thrown after calling Gmail.Users.Threads.get() | ||
| // maybe because a specific thread contains too many messages | ||
| // best to skip the thread | ||
| return null; | ||
| } | ||
| // Handle retries on UrlFetch calls with muteHttpExceptions | ||
| if (noError && typeof response.getResponseCode === "function") { | ||
| isUrlFetchResponse = true; | ||
| var responseCode = response.getResponseCode(); | ||
| // Only perform retries on error 500 for now | ||
| if (responseCode === 500) { | ||
| error = response; | ||
| noError = false; | ||
| } | ||
| } | ||
| // Return result that is not an error | ||
| if (noError) return response; | ||
| // Process error retry | ||
| if (!isUrlFetchResponse && error.message) { | ||
| // Check for errors thrown by Google APIs on which there's no need to retry | ||
| // eg: "Access denied by a security policy established by the administrator of your organization. | ||
| // Please contact your administrator for further assistance." | ||
| if (error.message.indexOf('Invalid requests') !== -1 | ||
| || error.message.indexOf('Access denied') !== -1 | ||
| || error.message.indexOf('Mail service not enabled') !== -1) { | ||
| throw error; | ||
| } | ||
| if (n === 5) { | ||
| // 'User-rate limit exceeded' is always followed by 'Retry after' + timestamp | ||
| // Maybe we should parse the timestamp to check how long we need to wait | ||
| // and if we should abort or not | ||
| if (e.message && e.message.indexOf('User-rate limit exceeded') !== -1) { | ||
| ErrorHandler.logError(e, { | ||
| shouldInvestigate: true, | ||
| failedAfter5Retries: true, | ||
| context: "Exponential Backoff" | ||
| }); | ||
| return null; | ||
| } | ||
| // Investigate on errors that are still happening after 5 retries | ||
| // Especially error "Not Found" - does it make sense to retry on it? | ||
| ErrorHandler.logError(e, { | ||
| failedAfter5Retries: true, | ||
| context: "Exponential Backoff" | ||
| }); | ||
| throw e; | ||
| // TODO: YAMM specific ?: move to YAMM code | ||
| else if (error.message.indexOf('response too large') !== -1) { | ||
| // Thrown after calling Gmail.Users.Threads.get() | ||
| // maybe because a specific thread contains too many messages | ||
| // best to skip the thread | ||
| return null; | ||
| } | ||
| } | ||
| } | ||
| // Action after last re-try | ||
| if (isUrlFetchResponse) { | ||
| ErrorHandler.logError(new Error(response.getContentText()), { | ||
| shouldInvestigate: true, | ||
| failedAfter5Retries: true, | ||
| urlFetchWithMuteHttpExceptions: true, | ||
| context: "Exponential Backoff" | ||
| }); | ||
| return response; | ||
| } | ||
| else { | ||
| // 'User-rate limit exceeded' is always followed by 'Retry after' + timestamp | ||
| // Maybe we should parse the timestamp to check how long we need to wait | ||
| // and if we should abort or not | ||
| // 'User Rate Limit Exceeded' (without '-') isn't followed by 'Retry after' and it makes sense to retry | ||
| if (error.message && error.message.indexOf('User-rate limit exceeded') !== -1) { | ||
| ErrorHandler.logError(error, { | ||
| shouldInvestigate: true, | ||
| failedAfter5Retries: true, | ||
| context: "Exponential Backoff" | ||
| }); | ||
| Utilities.sleep((Math.pow(2, n) * 1000) + (Math.round(Math.random() * 1000))); | ||
| return null; | ||
| } | ||
| // Investigate on errors that are still happening after 5 retries | ||
| // Especially error "Not Found" - does it make sense to retry on it? | ||
| ErrorHandler.logError(error, { | ||
| failedAfter5Retries: true, | ||
| context: "Exponential Backoff" | ||
| }); | ||
| throw error; | ||
| } | ||
@@ -90,2 +138,20 @@ } | ||
| /** | ||
| * Helper function to automatically handles exponential backoff on UrlFetch use | ||
| * | ||
| * @param {string} url | ||
| * @param {Object} params | ||
| * | ||
| * @return {UrlFetchApp.HTTPResponse} - fetch response | ||
| */ | ||
| function urlFetchWithExpBackOff(url, params) { | ||
| params = params || {}; | ||
| params.muteHttpExceptions = true; | ||
| return ErrorHandler.expBackoff(function(){ | ||
| return UrlFetchApp.fetch(url, params); | ||
| }); | ||
| } | ||
| /** | ||
| * If we simply log the error object, only the error message will be submitted to Stackdriver Logging | ||
@@ -148,2 +214,3 @@ * Best to re-write the error as a new object to get lineNumber & stack trace | ||
| expBackoff: expBackoff, | ||
| urlFetchWithExpBackOff: urlFetchWithExpBackOff, | ||
| logError: logError | ||
@@ -150,0 +217,0 @@ }; |
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
9042
23.54%208
30%2
Infinity%2
Infinity%