Googlesheets check if last execution failed - google-apps-script

I have a google sheet with a trigger that kicks off some code at 2 am each night.
sometimes the code fails due to various reason like network issue, or timing out because the site is busy and responses are slow (make numerous api calls)
I was thinking of putting in a code than runs based on a trigger every 15 minutes, to see if the last execution failed, then run my code again.
Been googling and search stackoverflow, but can't find a starting point on how to achieve this.
Basically I want to know if the last execution (which I can see manually in the executions screen) has a failed or time-out status, if it does I'll kick off my code again.

Use exponential backoff. You may want to try the exponentialBackoff_() function, like this:
function myFunctionThatRunsOnATrigger() {
exponentialBackoff_(myFunctionThatSometimesFails);
}
function myFunctionThatSometimesFails() {
//...
}

Related

Read/Write from Sheets is suddenly incredibly slow

I have a large script project that I've been working on for a couple of years that our company is using to track production in a manufacturing environment. Typically, the doGet function that loads the web interface for the tracking tool will execute in 5-15 seconds and is very snappy and responsive. However, since yesterday morning that function is taking 60-90 seconds per execution, and occasionally the web app doesn't open at all (even though I don't get a failure in the log for the doGet function). I've been out of vacation since last week and I'm the only developer with access to the code, so nothing in the code base has changed, and the underlying data in a Google sheet doesn't seem to have had any major shifts either.
I've narrowed things down to see that the reads/writes from/to Google Sheets is the main source of the slow down. I'm reading the data in a batch with getValues(), but a single call to that function on the ~850 rows x 9 columns is now taking almost 20 seconds, where the doGet function (which includes 3-4 getValues calls) ran in less than that as of a few days ago.
I'm completely at a loss for how to debug this issue. Here are a few lines of code from the beginning of my doGet function if it helps. There is more to the function than this, but I can look at the time stamps on the Logger statements to tell that this getValues is running way too slow.
var ss = SpreadsheetApp.openById("SPREADSHEETIDHERE");
var pst = ss.getSheetByName("Panel Status Tracker");
Logger.log("Start Panel Data Get")
var panelData = pst.getRange(9, 1, pst.getLastRow()-8, 8).getValues();
Logger.log("End Panel Data Get")
TIA!
These symptoms would usually suggest that the number of rows in the sheet has increased. Remove any unneeded blank rows at the bottom of the sheet and see if that helps.
If blank rows keep reappearing, chances are that you have a erroneous array formula somewhere in the sheet that causes runaway expansion.
Try adding console.time('sec1') and console.timeEnd('sec1') at various sections of your code to figure out which section takes the most time. If you figure out the section of code, try figuring out the exact line by adding subsections within that section.
console.time()

Exception handling with Realbrowserlocusts

In using realbrowserlocusts class it appears that I'm limited in any exception handling.
The only reference that partially works is: self.client.wait.until(EC.visibility_of_element_located ....
In a failed condition where the element is not found the script simply starts over again. With the script I'm working with I need to maintain a solid session state; I need to throw and exception(report an error), log the user out and then let the script start over again. I've been testing out the behavior with the locust.py script that Nick B. created with several approaches to "try, except" and they work running without realbrowserlocusts (selenium only) but with it the execution just stops.
Any examples would be greatly appreciated.
In its current format I've been able to run 3x the amount of a browser-based load per/agent/slave than our commercial tool. My goal is to replace it with a locust/selenium approach.
locust-plugins's WebdriverUser has a little bit better exception handling I think. A failure to find an element will log a failed request and if you use RescheduleTaskOnFail (as in the the example) it will restart the task when that happens.
https://github.com/SvenskaSpel/locust-plugins/blob/master/examples/webdriver_ex.py

google.script.run is NOT running every time it is called. Some times the function runs, other times it does nothing

In Google apps script when using a client sided .HTML file you can call a server sided script using google.script.run.(Function name).
You can see the related documentation here: https://developers.google.com/apps-script/guides/html/reference/run
Now this script has been working with no problems over the first 6 months of its lifetime or so. I have not touched the program and I have not been notified or have located any newly deprecated code.
Over the course of the last couple months however, my users have been reporting that when they finish interacting with the HTML document, nothing happens when they close it and they have to repeat the entire process 3 or sometimes even 4 times before they will get it to go through.,
This means that when the user closes the client sided HTML window, the server sided function should be called to handle the remaining tasks but in some cases is not. This issue is completely random, and does not seem to be caused by anything specific.
I have taken some steps myself to attempt to solve the issue. I have wrapped the entirety of the code in try catch blocks, including the .HTML and .GS files. This means that if literally ANYTHING goes wrong in ANY script, I will be notified of it immediately. However, despite this being the case I am yet to receive any emails of it failing even though I watch it fail with my own eyes. I have added log commands before and after this function to see if it stops working all together or continues. In every case regardless of whether the function call is successful or not the log commands go through.
To me this can only mean that for some reason the function google.script.run is not working properly, and is failing to run the associated function, but is not returning an error message or stopping the script.
I am at an absolute loss since I have no error message, no reproducible steps, and no history of this being a problem before while suddenly starting to get worse and worse over time. I have checked Google's issue tracker to no results. If anyone else is using this function and is having problems I would love you to share your experiences here. If you have a solution please let me know as soon as possible. If I can't fix this issue I am going to have to use a new platform entirely.
Edit 10/2:
After looking further into this issue I have discovered a list of all executions on this project. I can see what functions were executed, when, and how long they took to execute. I can see that when the function that opens the HTML service is ran, the next function that should run does not always appear in the list. And when it doesn't, I can see that the user repeated their steps until it did run. This supports my theory that the function just isn't running when it should be after being called my script.run
Tl;dr: The affected computers are running so slowly that google.script.host.close would run before google.script.run.functionName() is able to be called and the information passed from the client to server, causing the function to never run but also not return an error. Adding Utilities.sleep(1000) fixes the issue.
I'm answering here in the situation that someone stumbles upon this thread in the future because they're having similar problems.
I was able to fix the issue by adding two lines of code between
google.script.run and google.script.host.close.
I added Google's Utilities.sleep(1000) to force the computer to wait one second between executing the function and closing the HTML window. I also added an HTML alert that shows that the function was called and didn't suffer from a runtime error.
I don't know exactly why this seems to have fixed the issue but I have a theory.
I have about 20 computers this spreadsheet runs on. Only about 6 of them were having the issue, and this wasn't brought to my attention until recently. As it turns out the 6 computers that were having the issue were the slowest computers of the bunch.
My theory is that the computers were so slow, and the internet bandwidth was fluctuating so much that the computer simply didn't have time to call google.script.run and pass off the information from the client sided HTML window that it simply got closed and cut off when google.script.host.close was run. This means that the function will not exist in the execution transcripts or history, nor will there be any sort of runtime error. All of those things were true in my situation. This also explains why I never had the issue on any of my own equipment in a testing environment since it didn't suffer from any slowdowns the other computers were having.
By adding both Utilities.sleep(1000) and the UI alert this forces the javascript to not continue to google.script.host.close until the user interacts with the UI alert (Which is just a confirmation window with an OK button) and afterwards waits a full second. This sacrifices a tiny bit of user friendly-ness for a more functional script. Since I have implemented this "fix" none of my users are reporting any issues and all of my execution history looks just fine.
Hopefully this helps any future passerbys.
In the comments you posted this function snippet:
Here is a basic copy of the script that utilizes google.script.run:
function onFailure(error) {
MailApp.sendEmail("sparkycbass#gmail.com", "Order book eror", "ERROR: " + error.message);
google.script.host.close();
}
function handleFormSubmit(formObject) {
google.script.run.withFailureHandler(onFailure).processForm(formObject)
google.script.host.close();
}
The problem here is that google.script.run is asynchronous - the call to your server-side function processForm is not guaranteed to be even initiated before the call to google.script.host.close() is made:
Client-side calls to server-side functions are asynchronous: after the browser requests that the server run the function doSomething(), the browser continues immediately to the next line of code without waiting for a response. This means that server function calls may not execute in the order you expect. If you make two function calls at the same time, there is no way to know which function will run first; the result may differ each time you load the page. In this situation, success handlers and failure handlers help control the flow of your code.
A proper pattern is to only call "destructive" commands - such as closing the host and therefore unloading all the relevant Apps Script instances - after the server has indicated the async operation completed. This is within the success handler of the google.script.run call:
.html
function onFailure(error) { // server function threw an unhandled exception
google.script.run.sendMeAnEmail("Order book error", "ERROR: " + error.message);
console.log(error);
document.getElementById("some element id").textContent = "There was an error processing that form. Perhaps try again?"
}
function onSuccess(serverFunctionOutput, userObj) {
// do stuff with `serverFunctionOutput` and `userObj`
// ...
google.script.host.close();
}
function handleFormSubmit(formObject) {
google.script.run
.withFailureHandler(onFailure)
.withSuccessHandler(onSuccess)
.processForm(formObject);
}
.gs
function processForm(formData) {
console.log({message: "Processing form data", input: formData});
// ...
}
function sendMeAnEmail(subject, message) {
console.log({message: "There was a boo-boo", email: {message: message, subject: subject}});
MailApp.sendEmail("some email", subject, message);
}

Google Cloud Function: lazy loading not working

I deploy a google cloud function with lazy loading that loads data from google datastore. The last update time of my function is 7/25/18, 11:35 PM. It works well last week.
Normally, if the function is called less than about 30 minutes since last called. The function does not need to load data loaded from google datastore again. But I found that the lazy loading is not working since yesterday. Even the time between two function is less than 1 minute.
Does anyone meet the same problem? Thanks!
The Cloud Functions can fail due to several reasons such as uncaught exception and internal process crashes, therefore, it is required to check the logs files / HTTP responses error messages to verify the issue root cause and determine if the function is being restarted and generating Function execution timeouts that could explain why your function is not working.
I suggest you take a look on the Reporting Errors documentation that explains the process required to return a function error in order to validate the exact error message thrown by the service and return the error at the recommended way. Keep in mind that when the errors are returned correctly, then the function instance that returned the error is labelled as behaving normally, avoiding cold starts that leads higher latency issues, and making the function available to serve future requests if need be.

Why is a google.script.run call being repeated?

I am calling a function on the server that adds a few hundred objects to the ScriptDB database from the client using google.script.run. However, I have found that the server function is called more than once so the database ends up with duplicates of these objects.
function serverFunction(bigarray) {
// This function is called multiple times
db.saveBatch(bigarray);
}
Yet I can verify that the code on the client that calls serverFunction is only run once.
function clientFunction() {
alert("This function is only called once.");
google.script.run.serverFunction(bigarray);
}
Could my server code be timing out and getting run again automatically by GAS?
If so, how long is the time out and is this functionality documented anywhere?
Is there any way I can avoid this?
Its currently 30 seconds. This is a known issue and will be fixed fairly soon. (Its not a regression per se since its been like this since day 1 but I need to fix it to match the scripts own five minute timeout).