'Script to fetch data ; not all data is returned

I am making a google sheet script that loops trough all rows and fetches API data, then pastes all the results in a column all at once. All went well ( script returned all row data) until I started using below snippet instead of referring to a sheet name.

var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();

Now it returns all chunks it could fetch within the 5 mins it can run, then restarts with next trigger and returns a chunk again. The script takes much longer now.

First solution I could think of is making nested functions, so that not the whole script (including the loading of the active sheet) is reran, but only the fetch part. But now it gives me 'data is not defined' error. I think possibly because every time the script terminates due to google time limit, data gets wiped and has to be fetched again.

How can I solve this, activesheet is ideal as I want to be able to run this script with a button within two different tabs. But then it should work properly.

Code that goes wrong(returns a chunk(e.g. 80 rows), not all 400 rows):

/** GLOBAL PARAMETERS */

  // Serp API key
  var API_KEY = '12345';

  // key columns
  var COL_DOMAIN = 2;
  var COL_QUERY = 3;
  var COL_RANK = 5;
  var COL_GL = 8;

/** END: GLOBAL PARAMETERS */



/** 
 * Main function: gets search ranks using the Serp API
 */
function getRank() {

  // start timer and delete active triggers
  var timeStart = new Date();
  deleteTriggers();

  // Spreadsheet and sheet
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getActiveSheet();

  // get data from all rows in a 2-d array
  // array indices start at "0" instead of "1"
  // so to get row 1 it would be element 0 in the array and so on...
  var LR = sheet.getLastRow();
  var data = sheet.getRange(1, 1, LR, 18).getValues();

  // loop through all rows
  // starting at row = 3 (array element index = 2)
  for (var i = 2; i < data.length; i++) {

    console.log(i);

    // skip if procesed before
    var row = data[i];
    if (row[COL_RANK - 1] != '') {
      continue;
    }

    // process row
    try {

      // get parameters
      var domain = row[COL_DOMAIN - 1];
      var query = row[COL_QUERY - 1];
      var goog = row[COL_GL - 1];
      var gl = goog;
      var hl = goog;
      if (gl == 'co.uk') {
        gl = 'uk'
        hl = 'en'
      }
      else if (gl == 'com') {
        gl = 'us'
        hl = 'en'
      }

      // send API request
      var url = 'https://serpapi.com/search'
        + '?q=' + encodeURIComponent(query)
        + '&gl=' + gl
        + '&hl=' + hl
        + '&output=rank:' + encodeURIComponent(domain)
        + '&google_domain=google.' + goog
        + '&num=100'
        + '&api_key=' + API_KEY;
      var rank = UrlFetchApp.fetch(
        url, 
        { 
          'muteHttpExceptions': false 
        }
      ).getContentText();

      // update sheet with result
      sheet.getRange(i + 1, COL_RANK).setValue(rank);
      sheet.getRange(1,2).setValue(Date());
      
      // sleep for X milli-seconds
      Utilities.sleep(1);

      // check timer
      if (isTimeUp(timeStart)) {
        addTriggers();
        return;
      }
    
    } 
    catch (error) {
    
      sheet.getRange(i + 1, COL_RANK).setValue("Check of url(kolom B), afgesproken positie(D) of land(H) ontbreekt");
      continue;
    
    }

  }

}



/**
 * Checks if script execution time has hit the limit
 * default = 5 minutes if the minutes parameter is not passed to the function
 */
function isTimeUp(timeStart, minutes=5) {

  var now = new Date();
  return now.getTime() - timeStart.getTime() > minutes * 60 * 1000;

}



/**
 * Sets up a time trigger for the function to run in one minute
 */
function addTriggers() {

  // delete active triggers
  deleteTriggers();

  // create new trigger
  ScriptApp.newTrigger('getRank')
    .timeBased()
    .after(60 * 1000)
    .create();

}


/**
 * Deletes active triggers
 */
function deleteTriggers() {

  var triggers = ScriptApp.getProjectTriggers();
  for (var i = 0; i < triggers.length; i++) {

    ScriptApp.deleteTrigger(triggers[i]);

  }

}


Solution 1:[1]

I have found a simple solution. Using activesheet apparantly does not work well with generating triggers. So the trigger to rerun the script after timeout does not get executed.

I have stored the name of the active sheet in a variable and passed this on to getSheetByName like this and now script works, now I can run script on several sheets:

var name = ss.getActiveSheet().getName();
var sheet = ss.getSheetByName(name);

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Andriy Lozynskiy