【问题标题】:exceeded maximum execution time, google sheet, how to improve it?超过最大执行时间,google sheet,如何改进?
【发布时间】:2020-07-08 08:03:47
【问题描述】:

大家早上好

我来看你是因为在努力使我的谷歌脚本工作之后,在执行页面上我看到我的脚本工作,但是在我的谷歌工作表上我有一个错误:“超过最大执行时间”。我在互联网上看到自定义 google 脚本函数只留下 30 秒的执行时间,我不知道该怎么做?添加代码来调整此功能?我承认我不明白自定义函数和谷歌应用脚​​本之间的区别,但我知道脚本有 6 分钟的执行时间......这是我的代码摘录:

// Standard functions to call the spreadsheet sheet and activesheet
function GetPipedriveDeals2() {
  let ss = SpreadsheetApp.getActiveSpreadsheet();
  let sheets = ss.getSheets();
  let sheet = ss.getActiveSheet();

   //the way the url is build next step is to iterate between the end because api only allows a fixed number of calls (100) this way i can slowly fill the sheet.
  let url    = "https://laptop.pipedrive.com/v1/products:(id)?start=";
  let limit  = "&limit=500";
  //let filter = "&filter_id=64";
  let pipeline = 1; // put a pipeline id specific to your PipeDrive setup 
  let start  = 1;
  //let end  = start+50;
  let token  = "&api_token=XXXXXXXXXXXXXXXXXXXXXXXX"
  

  let response = UrlFetchApp.fetch(url+start+limit+token); //
  let dataAll = JSON.parse(response.getContentText()); 
  let dataSet = dataAll;
  //let prices = prices;
  //create array where the data should be put
  let rows = [], data;
  for (let i = 0; i < dataSet.data.length; i++) {
  data = dataSet.data[i];
    rows.push([data.id,
               GetPipedriveDeals4(data.id)
               ]);
  }

  Logger.log( 'function2' ,JSON.stringify(rows,null,8) );   // Log transformed data

  return rows;
}

// Standard functions to call the spreadsheet sheet and activesheet
function GetPipedriveDeals4(idNew) {
  let ss = SpreadsheetApp.getActiveSpreadsheet();
  let sheets = ss.getSheets();
  let sheet = ss.getActiveSheet();

   //the way the url is build next step is to iterate between the end because api only allows a fixed number of calls (100) this way i can slowly fill the sheet.
  let url    = "https://laptop.pipedrive.com/v1/products/"+idNew+"/deals:(id,d93b458adf4bf84fefb6dbce477fe77cdf9de675)?start=";
  let limit  = "&limit=500";
  //let filter = "&filter_id=64";
  let pipeline = 1; // put a pipeline id specific to your PipeDrive setup 
  let start  = 1;
  //let end  = start+50;
  let token  = "&api_token=XXXXXXXXXXXXXXXXXXXXXX"
  

  let response = UrlFetchApp.fetch(url+start+limit+token); //
  let dataAll = JSON.parse(response.getContentText()); 
  let dataSet = dataAll;
   //Logger.log(dataSet)
  //let prices = prices;
  //create array where the data should be put
  let rows = [], data;
  if(dataSet.data === null )return
  else {
    for (let i = 0; i < dataSet.data.length; i++) {
      data = dataSet.data[i];
      let idNew = data.id; 
      rows.push([data.id, data['d93b458adf4bf84fefb6dbce477fe77cdf9de675']]);
    }
  
  Logger.log( 'function4', JSON.stringify(rows,null,2) );   // Log transformed data
  return rows;
  }
}

提前谢谢大家。

编辑:--------------FOR EACH LOOP--------- -------------------


function getPipedriveDeals(start = 0,apiRequestLimit = 39) {
  console.log("start="+start);
  //Make the initial request to get the ids you need for the details.
  var idsListRequest = "https://laptop.pipedrive.com/v1/products:(id)?start=";
  var limit = "&limit=" + apiRequestLimit;
  var token = "&api_token=XXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
  var response = UrlFetchApp.fetch(idsListRequest + start + limit + token);
  var data = JSON.parse(response.getContentText()).data;
  
  //For every id in the response, construct a url (the detail url) and push to a list of requests
  var requests = [];
  console.log("data="+data);
  data.forEach(function(product) {
    var productDetailUrl = "https://laptop.pipedrive.com/v1/products/" + product.id + "/deals:(id,d93b458adf4bf84fefb6dbce477fe77cdf9de675)?start=";
    requests.push(productDetailUrl + start + limit + token)
  });
  
  //With the list of detail request urls, make one call to UrlFetchApp.fetchAll(requests)
  var responses = UrlFetchApp.fetchAll(requests);
  return [responses,JSON.parse(responses[0].getContentText()).additional_data.pagination.more_items_in_collection];
  
}

function getAllDeals(){
  var allResponses = [];
  for(var i = 0; i<500; ){ 
    var deals = getPipedriveDeals(start=i);
    deals[0].forEach((response)=>{allResponses.push(response)});
  if(deals[1]){
    // If there are more items sleep for 1000 milliseconds
    Utilities.sleep(1000);
    i+=39;
  }
  else{
    console.log("No more items in collection.");
    break;
  }
}
console.log("allResponses="+allResponses);
return allResponses;
}

关于日志中的奇怪行为:

-------------------编辑编号2------- --------------------------

直到现在我执行=getPipedriveDeals()它返回False(就像我在评论中所说的那样)以及当我尝试删除additional_data.pagination.more_items_in_collection(因为它对我来说不是很有用)我不知道为什么但是脚本不再起作用了,我在选择要返回的数据时遇到了一些困难。


【问题讨论】:

  • 如果在循环中使用fetch 是您问题的主要原因,那么使用fetchAll 怎么样? Ref 但我不确定你的实际情况。例如,在您的脚本中,sssheetssheet 的值是多少?这些不是用的吗?
  • 您好@Tanaike,感谢您的快速回复!值“ss, sheet, sheet”用于选择谷歌表,我还注意到在我的第二个函数中它们可能不是必需的,它为我节省了大约 8 秒的时间来删除它们。我认为您对 fetch 的看法是正确的,只是我真的不知道如何在当前状态下实现 FetchAll ...根据文档,它必须附加到一个或多个请求,而我不知道真的不知道如何修改代码来做到这一点而不破坏一切我花了很长时间编写它并且我得到了一点帮助......再次感谢

标签: function loops google-apps-script optimization google-sheets


【解决方案1】:

您可以使用UrlFetchApp.fetchAll(requests) 来节省配额,并且可能会节省很多脚本执行时间。

我已经删除了您代码中的一些冗余,以使以下示例显示您的案例使用 fetchAll

示例:

function getPipedriveDeals(start = 0,apiRequestLimit = 50) {
  console.log("start="+start);
  //Make the initial request to get the ids you need for the details.
  var idsListRequest = "https://laptop.pipedrive.com/v1/products:(id)?start=";
  var limit = "&limit=" + apiRequestLimit;
  var token = "&api_token=xxxxxxxxxxx";
  var response = UrlFetchApp.fetch(idsListRequest + start + limit + token);
  var data = JSON.parse(response.getContentText()).data;
  
  //For every id in the response, construct a url (the detail url) and push to a list of requests
  var requests = [];
  console.log("data="+data);
  data.forEach(function(product) {
    var productDetailUrl = "https://laptop.pipedrive.com/v1/products/" + product.id + "/deals:(id,d93b458adf4bf84fefb6dbce477fe77cdf9de675)?start=";
    requests.push(productDetailUrl + start + limit + token)
  });
  
  //With the list of detail request urls, make one call to UrlFetchApp.fetchAll(requests)
  var responses = UrlFetchApp.fetchAll(requests);
  return [responses,JSON.parse(responses[0].getContentText()).additional_data.pagination.more_items_in_collection];
}

现在假设您有一个计划,将配额限制为每 2 秒 50 个请求。

您可以将 fetchAll 调用中的请求限制为 50,并引入 delay/sleep of (X) milliseconds 以发起第二个请求,从 id=50 开始,例如:

function getAllDeals(){
  var allResponses = [];
  for(var i = 0; i<500; ){ 
    var deals = getPipedriveDeals(start=i);
    deals[0].forEach((response)=>{allResponses.push(response)});
  if(deals[1]){
    // If there are more items sleep for 1000 milliseconds
    Utilities.sleep(1000);
    i+=50;
  }
  else{
    console.log("No more items in collection.");
    break;
  }
}
console.log("allResponses="+allResponses);
return allResponses;
}

【讨论】:

  • 感谢您的回复!看起来不错,但我有一个错误:{"success":false,"error":"request over limit","errorCode":429} 与您的脚本没有直接关系,但由于 API 的限制:pipedrive.readme.io/docs/core-api-concepts-rate-limiting 我想如果您有想法,我会尝试在通话之间延迟欢迎。再次感谢您的帮助,这太棒了
  • 我很高兴它有帮助!是的,429 错误是“请求太多”,因此您可能受到限制。所以你应该考虑这些限制。您不太可能成功实施延迟,因为 fetchAll 将发出所有请求,并且您不可能添加延迟,但也许您可以将同时请求的数量控制在您的 API 帐户的速率之下。请看what to do when someone answers
  • 您好@Aerials,感谢您的帮助,但我仍然有 2 个电源问题,429 错误,我不知道如何解决它,我还注意到此代码发送回空对象,我想我必须声明我想要返回的对象,但是,我不知道在哪里表明这一点......(我将编辑我的第一篇文章以放置 GAS 执行的图像)......对于 429 错误我想将 Oauth 放在我的脚本中以增加我的请求数量,但这似乎非常困难,您还有其他想法吗?即使我必须重写部分功能。再次感谢队友
  • @AlbanM 为函数返回一些东西,你只需要添加一个返回语句。我建议你找出你的最大每日请求配额,并尊重它们。我添加了一个“apiRequestsLimit”参数,您可以使用它来限制您向 pipedrive API 发出的请求数。即使您拨打fetchAll 一次电话,您的代币仍被代码使用多达 500 次,显然超过了速率限制。查看更新的答案。
  • 事实上我找到了我的请求配额,它是每 2 秒 80 次调用,如果我使用 Oauth,它是每 2 秒 360 次调用。使用你给我的新代码我现在有一个错误12:40:04 Erreur TypeError: Cannot read property 'forEach' of null at getPipedriveDeals(Copie de importNamesTypes:12:8) 我想这是因为请求有时返回一个空对象?谢谢
猜你喜欢
  • 2016-05-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-29
  • 2013-04-01
  • 1970-01-01
相关资源
最近更新 更多