We're working with Spreadsheets and Apps-Script to do some automation, therefore we've set up some time based triggers, some hourly, some daily based, all set up in the apps-script dashboard. It happens more and more often, that the triggers simply don't run. They're just not executed, so I don't see any failure in the dashboard (because the code is valid, though).
I thought, it was about the .getActiveSpreadSheet() method which might not work, when the sheet is not open or visible (which it would be in the most cases), but I recently have a sheet where I open it by id (openById), and the trigger still works just as he pleases.
Simple example code is:
function testTrigger(){
var sheet = SpreadsheetApp.openById($sheetid).getSheetByName("ha")
sheet.getRange("A1").setValue(new Date());
Logger.log("test");
}
And before I used
function testTrigger(){
var sheet = SpreadsheetApp.getActiveSpreadsheet.getSheetByName("ha")
sheet.getRange("A1").setValue(new Date());
Logger.log("test");
}
The trigger for this function is set to fire every minute. As I can see in the sheet, the last time it ran was 12:35:48, but it's now 12:40. So why isn't it working?
By the time I'm writing this, it suddenly fired at 12:40:48. But now it's 12:44 again, so there are already 3 runs missing! Why does this keep happening?
And: Would SpreadsheetApp.getActiveSpreadsheet.getSheetByName("ha") even work with a closed sheet? Has the sheet to be open AND active in the browser? We were using Spreadsheets and Apps-Script for months now, I used getActiveSpreadsheet.getSheetByName("ha") every time and it worked. It seems, the time driven triggers are buggy atm, I have no other conclusion (since the code and everything else is valid).
Is there any way to find out, why a trigger didn't fire (beside a code error, which I would of course see in the dashboard).
And would these problems also occur, if I would use programmatical triggers?
Thanks in advance!
Here's an image of the problem (nothing changed in the code or in the trigger during these runs):
To answer some your questions
As specified by the documentation for time-driven triggers "The time may be slightly randomized — for example, if you create a recurring 9 a.m. trigger, Apps Script chooses a time between 9 a.m. and 10 a.m"
If instead you create manually a ClockTriggerBuilder with the parameter nearMinute(minute), this "Specifies the minute at which the trigger runs (plus or minus 15 minutes)". In other words: You cannot expect from the Apps Script triggers to run precisely at the time you would like them to.
SpreadsheetApp.getActiveSpreadsheet() works if you have a bound script, rather than an alone-standing script. In any case, to avoid error sources, it is wise to use SpreadsheetApp.openById(id) instead of SpreadsheetApp.getActiveSpreadsheet()
You can supervise your triggers und executions and My triggers, however from your description it seems like the trigger is fired correctly, just not exactly at the time you would desire.
Related
Probably the answer to this is simple but I am having a tough time getting my head around it.
I have a spreadsheet used by many users. I want custom onEdit and onOpen functions to run only for the user who triggers then. For example - if person B opens the spreadsheet, then only his custom onOpen trigger should run, not the custom onOpen triggers for the other users. Likewise if the user edits a cell only his custom onEdit should run.
Currently how I have set it up everyone has his own triggers but they all run the same script every time there is a trigger by any user, meaning the trigger runs 4x for no reason and it's slowing down the spreadsheet, and it also wastes script time usage for the other users who are not opening or editing the sheet.
You can have separate functions for each user and have code dynamically check for current user and run the function of current user only.
See here for getting current user. Link
Assuming the functions are the same but you just aren't wanting it to run for some users, you could use PropertiesService to store a user property to identify if it should run or not. You have to make some UI method to set the property and then you would check for the property at the beginning of each of your functions. Technically the functions would run but you could return out of them if you don't want to finish the logic.
I have been implementing a spreadsheet for about a year and a half now that constantly runs a number of trigger based GAS functions to check data, send emails based on that data, and update a staff calendar.
All of the time driven triggers are executing normally. I have not had an issue with them. However, the spreadsheet driven triggers (onEdit, onChange) are not working at all. I left work for a two week vacation and I did not change the script at all. When I came back, it no longer worked.
I deleted the trigger, recreated it, and switched between onEdit and onChange; the trigger will still not fire. The function that is triggered on edit is dependent on the event for it to execute properly. I test ran the function outside of the trigger and it failed where I expected it to (where the event dependant variables are) so there was no surprise there.
As far as I can tell, the spreadsheet driven triggers just won't fire at all. Does anyone know of any issues on Google's end, are spreadsheet driven triggers working for any of you guys? As far as I can tell the trigger just stopped working all together.
If I explicitly nest my function inside the onEdit() function in the script, it will execute, it won't if I just create a trigger, however it throws an error saying that the script does not have the permissions to execute MailApp.sendEmail() even though the app is already authorized to send emails as me.
Even more interesting, the functions executed with time driven triggers are still able to send emails and update my calendar.
It seems like the spreadsheet driven triggers have quit working all together.
Just to be clear I did not make the mistake of naming my function onEdit or onChange.
I have Google Spreadsheet named "TeamWork" and I share it with about 50 other users, they can edit different ranges ad sheets. Problem is that when some of them want to change the name of file, they just can do it, so time to time I have funny names for this file, like "teamNotWork" etc.
Is there a way to prevent anyone except owner from rename Spreadheet? If possible not using "onEdit" script trigger, because its using quota.
Thanks for help!
onOpen wont happen often enough and onEdit will consume too much quota.
instead, use a time based trigger (every minute or every 5 minutes) to rename the file if its not what you want.
it also has the advantage that it will work regardless of how users open the sheet (mobile or desktop).
I would try using onOpen trigger:
function onOpen() {
var file = SpreadsheetApp.getActiveSpreadsheet();
file.rename('TeamWork');
}
You may add one more time Driven trigger and launch it once a day when nobody works with file.
I recently created a script associated with a spreadsheet. It is a wood supply chain simulation game score viewer. Basically, it fetch (with Urlfetch) the game database to keep track of scores for every team playing in tables and graphs. The spreadsheet is then shared to every team member, which can see the progression of the game.
So I used an installable onMinute time trigger to refresh the spreadsheet with updated score from the database. Everythings was working, but recently, I started to receive app-script-notifications of failure with error :
Service invoked too many times for one day: urlfetch.
I then realised that the installable triggers are executed when the documment is not open, which is totally logic. Also, since developpement mode, I had quite a lot of the spreadsheat copy (je comprend pas sa), which explains the reach of my quota. Altough, I only need to refresh the scores for my application when the document is open.
Here are my questions :
Is the installable onMinute time trigger the right way to do that?
Is there a way to make the trigger run only when the document is open?
This is my first question here so feel free to post useful comments to allow me to improve.
Thank you.
Unless you can write code on the game side to push the changes to the spreadsheet, which would use less resource on both sides, a time-driven triggers seems like the only "automatic" way to go.
I say automatic, because you could change it to "on-demand". I mean, you could add a menu to your spreadsheet or an image (where you can assign to run a script on click), that will update the scores.
This could also be semi-dynamic, for example, when the user clicks the button, you start to update the scores automatically (setting up the time-driven trigger programatically) for the next 30 minutes or so.
Asking your question n.2: no, it is not possible. Well, only half-way. Because you can detect when the spreadsheet is opened (by setting a on-open trigger), but you can't know when it is closed.
What about using the onOpen event to programmatically create the following:
a new trigger that updates the spreadsheet every minute
a new hourly trigger that checks
if {a user property is set}
then deletes all the triggers
else set the user property
a onEdit trigger that unsets the previously mentioned user property
So that if a user hasn't edited the spreadsheet for an hour all the triggers stop
It's a bit convoluted but without an onClose event, convoluted is the best you can hope for.
Here is a piece of code I imagine that could maybe do what you want or at least get close...
I tried it on a testsheet (shared with authorization requested) and it works as expected, i.e the timer triggered function executes only if someone is editing the spreadsheet, otherwise it returns.
Let's say it's a proposal, you'll tell me if it meets your requirements ;-)
function onTimer() { // this function has a timer trigger set to 1 minute
var ss = SpreadsheetApp.openById('0AnqSFd3iikE3dG90MzRwX0FQUnoxTWZjcmtLSlVuT3c')
var sh = ss.getSheets()[0]
var logsheet = ss.getSheets()[1]
var formerUser = ScriptProperties.getProperty('lastUser')
if(formerUser=='nobody'){return}
ss.toast('The sheet is being edited by '+Session.getActiveUser());
ScriptProperties.setProperties({'lastUser': 'nobody'}, true);
logsheet.getRange(logsheet.getLastRow()+1, 1).setValue('onTimer function was running on '+
Utilities.formatDate(new Date(),'GMT+2','HH:mm'))
}
function onUserPresent(){ // this one has an onEdit installable trigger
ScriptProperties.setProperties({'lastUser': 'someone'}, true);
}
I'm playing with triggers.
In a spreadsheet, I have a function that inserts a date in a new row. Runs as a clock trigger every minute. Works fine if the spreadsheet is open or closed (loving that part).
In a standalone script, I setup a trigger for onEdit in the above spreadsheet. All it does is email me the e.value.
It works if I'm in the spreadsheet and just type in some characters in a cell.
What I'd "expect" is each time the date is inserted by the first trigger, it would trip the onEdit. Alas, it does not. Even if I run the insert date function outside of the trigger, my email onEdit trigger does not fire.
Any thoughts?
I ask, as my goal was to have scripts updating a sheet that kicked off an onEdit event.
Jim
UPDATE #1:
Maybe this code example helps?
I simplified this to one script inside a spreadsheet container. Each function works fine on their own and the second works if I do any interactive changes to the spreadsheet.
This is just exploration, so please ignore quota's or the utter nonsense of what I'm testing here :-)
insertClockTrigger: runs every minute, works fine
installableOnEdit: never triggers as an installable onEdit when insertClockTrigger fires
I'm curious why what looks to be an edit done by the insertClockTrigger is not firing an onEdit trigger. Do triggers not trigger triggers (could not help myself!)?
function insertClockTrigger() {
var sheet = SpreadsheetApp.openById('spreadsheet-ID').getSheets()[0];
var nDate = new Date();
sheet.getRange(sheet.getLastRow()+1,1,1,1).setValue(nDate).flush;
}
function installableOnEdit(e) {
GmailApp.sendEmail("some#email.com", "Test trig2", "FISH: "+e.value);
}
Call the onEdit function from the clock trigger function.
Also, you might hit a quota issue with running such a trigger every min.
Think I found an answer.
Henrique Abreu posted:
http://productforums.google.com/d/msg/apps-script/HmBg0p7dOZ8/xMb6wfcfvVQJ
Yes, "on edit" events are not called when the changes are made from
the code, they're are called only for manual changes. This behaviour
is intended by design, as to avoid unnecessary recursion problems.
Also, it just too easy to just call your desired on-edit function
directly from your code. i.e. when you script that inserts a new
ticket does so, it can just plainly call your "fundEmail" function,
there's no need for another trigger.
onEdit should be renamed to onUserEdit. It doesn't receive system changes, only direct user edits.
I haven't tested this, but onChange may do what you want.