arraysgoogle-apps-scriptlimitratesites

Save Google App Script state while parsing an object array and continue where left off later on


I am using this simple google app script to parse through all available Google Sites and dump the html content of individual pages. There are quite many pages so the script will eventually run into 6 minute time limit.

Is it possible to somehow use the PropertiesService to save the current progress (especially in the array loops) and continue where left off later on?

    var sites = SitesApp.getAllSites("somedomain.com");
    var exportFolder = DriveApp.getFolderById("a4342asd1242424folderid-");
            
            // Cycle through all sites
        for (var i in sites){
              var SiteName = sites[i].getName();
              var pages = sites[i].getAllDescendants();
              // Create folder in Drive for each site name
              var siteFolder = exportFolder.createFolder(SiteName)
        
        for (var p in pages){
                // Get page name and url
                var PageUrl = pages[p].getUrl();
             
               
                //Dump the raw html content in the text file
                var htmlDump = pages[p].getHtmlContent();
                siteFolder.createFile(PageUrl+".html", htmlDump)
                
              }
        }

I can image how one can use the Properties Service to store current line number in the Spreadsheet, and continute where left off. But how can this be done with array containing objects like Sites or Pages?


Solution

  • Using Objects with Properties Service

    According to the quotas the maximum size of something you can store in the properties service is 9kb. With a total of 500kb. So if your object is less than this size, it should be no problem. That said, you will need to convert the object to a string with JSON.stringify() and when you retrieve it, use JSON.parse.

    Working around the run time limit

    What is commonly done to work around the limit is to structure a process around the properties service and triggers. Essentially you make the script keep track of time, and if it starts to take a long time, you get it to save its position and then create a trigger so that the script runs again in 10 seconds (or however long you want), for example:

    function mainJob(x) {
      
      let timeStart = new Date()
      console.log("Starting at ", timeStart)
      
      for (let i = x; i < 500000000; i++){ // NOTE THE i = x
        
        // MAIN JOB INSTRUCTIONS
        let j = i
        // ...
      
        // Check Time
        let timeCheck = new Date()
        if (timeCheck.getTime() - timeStart.getTime() > 30000) {
          console.log("Time limit reached, i = ", i)
          
          // Store iteration number
          PropertiesService
              .getScriptProperties()
              .setProperty('PROGRESS', i)
          
          console.log("stored value of i")
          
          // Create trigger to run in 10 seconds.
          ScriptApp.newTrigger("jobContinue")
              .timeBased()
              .after(10000)
              .create()
          
          console.log("Trigger created for 10 seconds from now")
          return 0
        }
      }
      
      // Reset progress counter
      PropertiesService
              .getScriptProperties()
              .setProperty('PROGRESS', 0)
      
      console.log("job complete")
    }
    
    function jobContinue() {
      
      console.log("Restarting job")
      
      previousTrigger = ScriptApp.getProjectTriggers()[0]
      ScriptApp.deleteTrigger(previousTrigger)
      console.log("Previous trigger deleted")
      
      triggersRemain = ScriptApp.getProjectTriggers()
      console.log("project triggers", triggersRemain)
      
      let progress = PropertiesService
                       .getScriptProperties()
                       .getProperty('PROGRESS')
      
      console.log("about to start main job again at i = ", progress)
      
      mainJob(progress)
      
    }
    
    function startJob() {
      mainJob(0)
    }
    

    Explanation

    References