Search code examples
javascriptgoogle-apps-scripttriggersmethod-chaining

Chain methods for ClockTriggerBuilder


I have a GAS time based trigger that I would like to run at intervals of some combination of hours and minutes (i.e. the triggered function would run every 2 hours and 30 minutes, or every 4 hours and 15 minutes). So I am chaining the everHours and everyMinutes methods together and passing in values. However, Google Apps Script doesn't like this and I keep getting the following error:

Exception: The recurrence interval on the clock trigger has already been set.

This error occurs at the line containing the everyMinutes() method in the code below.

Is it not possible to chain these two methods? The GAS class ClockTriggerBuilder documentation doesn't explicitly say you can't chain them, but the error appears to indicate that you can't.

If Google Apps Script doesn't allow you to chain the everyHours() and everyMinutes() methods, is there some kind of a work around that would achieve a similar result? Perhaps chaining the everyHours() and nearMinute() methods?

The trigger this function runs sends data rows ("leads") to other spreadsheets ("clients"). Once all the leads have been sent for a day, another function kills this trigger, and then resets the trigger for the next day. I would like a different time interval to be passed for the following day.

Here is my code:

function createLeadTrigger(){
  let hours = 1 
  let minutes = 15
  Logger.log(`For today, leads will be sent to clients every ${hours} hours and ${minutes} minutes.`)
  ScriptApp.newTrigger('sendALeadToEachClient')
    .timeBased()
    .everyHours(hours)
    .everyMinutes(minutes)
    .create();
    
}

Solution

  • I have done something similar in the past that could help you. However, it might not be the most elegant solution since it does not work by updating the time driven trigger interval but tracking the last time the script ran based on a value stored in the Script Properties. There should be better ways to handle this, but so far this is the best to my knowledge.

    The solution consists of 2 functions, the first one "setTimeInterval" is the one that you can update the time interval by passing an array with 2 numbers [hour,minute]. And the second fuction "shouldRunScript()" (this is the function that you should the time driven trigger at lets say every 5 minutes).

    The reason why I used this approach in the past is to use this fuction to update multiple files by tracking different timeStamps so it is not needed to set multiple time triggers, not exactly what you need but the code I provide is updated to your needs.The downside of this approach is that a new execution will appear every 5 minutes in the execution log.

    //To this function you pass an array with 2 numbers, first hour and second the minutes EG. [1,15]
    function setTimeInterval (hourMinute) {
    
      const scriptProperties = PropertiesService.getScriptProperties();
      const hourProperty = scriptProperties.setProperty('Hour',hourMinute[0].toString());
      const minuteProperty = scriptProperties.setProperty('Minute',hourMinute[1].toString());
    
    }
    
    //this is the function that should be run by the time trigger
    function shouldRunScript() {
    
      //retreives Script Properties
      const scriptProperties = PropertiesService.getScriptProperties();
    
      //retreives as string the last time the script ran 
      const lastRunTimeStr = scriptProperties.getProperty('Last Run');
      const lastRunTime = null;
    
      //If the script never Ran before, then it will create that property and store a new Date
      if (lastRunTimeStr) {
        lastRunTime = new Date(lastRunTimeStr);
      } else {
        // set the "Last Time Run" value to the current time if it doesn't exist
        lastRunTime = new Date();
        scriptProperties.setProperty('Last Run', lastRunTime.toString());
      }
    
      // Get the "Hour" value as a number
      const hourStr = scriptProperties.getProperty('Hour');
      const hour = Number(hourStr);
    
      // Get the "Minute" value as a number
      const minuteStr = scriptProperties.getProperty('Minute');
      const minute = Number(minuteStr);
    
      // Calculate the difference between the current time and the Last RUn
      const now = new Date();
      const diffInMs = now.getTime() - lastRunTime.getTime();
      const diffInMinutes = Math.floor(diffInMs / 1000 / 60);
    
      // Check if the difference is higher than the hour and minutes
      if (diffInMinutes >= (hour * 60 + minute)) {
        
        scriptProperties.setProperty('Last Run', now.toString());
        
        //here you call your function that should do whatever you need in the correct interval
    
      } 
    }