Google app script exceeded maximum execution time

2.1k Views Asked by At

I am getting the error "exceeded maximum execution time" on running the below script. trying to run a cron on my website and each url takes time to process in my website which leads to exceeding the time limit. Once url processed in the website it shows the message from the link in the execution log. How can i make the script run again from start or from url it stopped.

function getUrls() {
try {
var urls = [ 'https://www.testurl.com/link1=processing',
             'https://www.testurl.com/link2=processing',
             'https://www.testurl.com/link3=processing',];

function getUrl(url) {
  var response = UrlFetchApp.fetch(url).getContentText();
  if ( response.indexOf("triggered") >-1 ) {
      Logger.log(response);
    }
  else if ( response.indexOf("complete") >-1 ) {
      Logger.log(response);
      response = UrlFetchApp.fetch(url).getContentText();
    }
  while ( response.indexOf("Records Processed") >-1 ) {
      Logger.log(response);
      return 0;
    }
  }

urls.forEach( getUrl );
}
catch(err) {
Logger.log(err);
}
}
4

There are 4 best solutions below

0
Neven Subotic On

Your while condition lasts forever. The result of the condition never changes therefore if it is true once, it will run forever.

Or, you are calling getUrl in your forEach and that also leads to it calling itself over and over again. I think that is the real issue.

1
Cooper On

Try this:

function getUrls() {
  const urls = ['https://www.testurl.com/link1=processing', 'https://www.testurl.com/link2=processing', 'https://www.testurl.com/link3=processing'];

  urls.forEach(u => {
    let response = UrlFetchApp.fetch(u).getContentText();
    if (~response.indexOf("triggered")) {
      Logger.log(response);
    }
  });
}

BitWise not

11
TheWizEd On

If I run each consecutively I get this. I hope this doesn't corrupt your data since it says it imports records but I have no idea where. I've added the code I ran that produced the log below.

function getUrls() {
  try {
    var urls = [ 'https://www.testurl.com/link1=processing',
                 'https://www.testurl.com/link2=processing',
                 'https://www.testurl.com/link3=processing',];

    function getUrl(url) {
      console.log("url = "+url)
      var start = new Date();
      var options = { 'method': 'get' };
      var response = UrlFetchApp.fetch(url, options);
      var end = new Date();
      console.log("response code = "+response.getResponseCode());
      console.log("elapsed time = "+((end.valueOf()-start.valueOf())/1000)+" sec.'");
      console.log("response text = "+response.getContentText());
    }

    var start = new Date();
    urls.forEach( getUrl );
    var end = new Date();
    console.log("total elapsed time = "+((end.valueOf()-start.valueOf())/1000)+" sec.");
  }
  catch(err) {
    Logger.log(err);
  }
}

5:27:21 AM  Notice  Execution started
5:27:22 AM  Info    url = xxxxxx
5:27:22 AM  Info    response code = 200
5:27:22 AM  Info    elapsed time = 0.671 sec.'
5:27:22 AM  Info    response text = {"status":200,"message":"#1 Cron job triggered."}
5:27:22 AM  Info    url = xxxxxx
5:27:25 AM  Info    response code = 200
5:27:25 AM  Info    elapsed time = 2.66 sec.'
5:27:25 AM  Info    response text = {"status":200,"message":"Import #1 complete"}
5:27:25 AM  Info    url = xxxxxx
5:28:39 AM  Info    response code = 200
5:28:39 AM  Info    elapsed time = 74.002 sec.'
5:28:39 AM  Info    response text = {"status":200,"message":"Records Processed 221. Records imported 220 of 600."}
5:28:39 AM  Info    url = xxxxx
5:29:56 AM  Info    response code = 200
5:29:56 AM  Info    elapsed time = 77.081 sec.'
5:29:56 AM  Info    response text = {"status":200,"message":"Records Processed 241. Records imported 240 of 600."}
5:29:56 AM  Info    total elapsed time = 154.448 sec.
5:29:55 AM  Notice  Execution completed
4
TheWizEd On

Here is what I have so far. I have an empty spread sheet. I'm not using your urls, simply making repeated calls to UrlFetchApp.fetch("http://www.google.com/");. You can duplicate and try it out. If I knew the best way to test for urls[3] completion I can work it into the script but for now simply testing against the number of urls. I've added a new function repeatUrl. I can't test it because I'm really not sure of the response that stops loop. But it should work. And because each google.script.run is only about 1-2 min. you should not exceed the time limit. (I think).

In the app script I have:

In Code.gs:

function onOpen() {
  var menu = SpreadsheetApp.getUi().createMenu("Fetch Urls");
  menu.addItem("Side Bar","showSideBar");
  menu.addToUi();
}

function include(filename) {
  return HtmlService.createHtmlOutputFromFile(filename)
      .getContent();
};

function showSideBar() {
  try {
    var html = HtmlService.createTemplateFromFile('HTML_Test').evaluate();
    SpreadsheetApp.getUi().showSidebar(html);
  }
  catch(err) {
    SpreadsheetApp.getUi().alert(err);
  }
}

function fetchUrl(url) {
  try {
    var response = UrlFetchApp.fetch("http://www.google.com/");
    console.log(response);
    return response.getResponseCode();
  }
  catch(err) {
    return "Error: "+err.message;
  }
}

I have HTML_Test (HTML file):

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body>
    <input type="button" value="Fetch Urls" onclick="fetchOnClick()">
    <?!= include("JS_Test"); ?>
  </body>
</html>

And finally I have JS_Test (HTML file):

<script>
  var urls = [ 'https://www.testurl.com/link1=processing',
               'https://www.testurl.com/link2=processing',
               'https://www.testurl.com/link3=processing'];    

  function fetchUrl( index ) {
    try {
      google.script.run.withSuccessHandler(
        function(response) {
          alert("index= "+index+" response= "+response);
          //if( response.includes("Error:") ) return;
          index++;
          if( index < urls.length ) {
            fetchUrl( index );
          }
        }
      ).fetchUrl(urls[index]);
    }
    catch(err) {
      alert("Error in fetchUrl: "+err);
    }
  }
  
  function repeatUrl(url) {
    try {
      google.script.run.withSuccessHandler(
        function(response) {
          alert(" response= "+response);
          if( respone.includes("Records imported") ) {
            repeatUrl(url);
          }
        }
      ).fetchUrl(url);
    }
    catch(err) {
      alert("Error in fetchUrl: "+err);
    }
  }

  function fetchOnClick() {
    try {
      fetchUrl(0);
      repeatUrl(url[3]);
    } 
    catch(err) {
      alert(err);
    }
  }    
</script>