我正在向我的Web应用发送5个请求:

import requests

backodds = "3.00"
layteam = "Flamengo"
layodds = "1.50"
advantage = "25.55"
webAppsUrl = "https://script.google.com/macros/s/XXXX/exec"

for i in range(5):
    requests.get(webAppsUrl + "?backteam=" + str(i) + "&backodds=" + backodds + "&layteam=" + layteam + "&layodds=" + layodds + "&advantage=" + advantage)

如果我可以等待每个请求执行,我可以这样离开我的Web应用程序:

function doGet(e) {
  const lock = LockService.getDocumentLock();
  if (lock.tryLock(360000)) {
    try {
      var backteam = e.parameter.backteam;
      var backodds = e.parameter.backodds;
      var layteam = e.parameter.layteam;
      var layodds = e.parameter.layodds;
      var advantage = e.parameter.advantage;

      Utilities.sleep(30000) // I swapped the tasks for a sleep just for testing

      var second_sheet = SpreadsheetApp.openById('XXXXXXX');
      var second_sheet_page = second_sheet.getSheetByName('STACKTEST');
      var r = 1;
      while (second_sheet_page.getRange(r, 1).getValue()) {
        r++;
      }
      second_sheet_page.getRange(r, 1, 1, 5).setValues([[backteam,backodds,layteam,layodds,advantage]]);
    } catch (e) {
      //pass
    } finally {
      lock.releaseLock();
    }
  } else {
    //pass
  }
}

由于我不想等待每个请求完成执行(因 for each 请求都需要30秒以上,而且我不在乎执行期间和之后会发生什么),因此我正在 for each 请求创建一个触发器:

var RECURRING_KEY = "recurring";
var ARGUMENTS_KEY = "arguments";

function setupTriggerArguments(trigger, functionArguments, recurring) {
  var triggerUid = trigger.getUniqueId();
  var triggerData = {};
  triggerData[RECURRING_KEY] = recurring;
  triggerData[ARGUMENTS_KEY] = functionArguments;

  PropertiesService.getScriptProperties().setProperty(triggerUid, JSON.stringify(triggerData));
}

function handleTriggered(triggerUid) {
  const lock = LockService.getDocumentLock();
  if (lock.tryLock(360000)) {
    var scriptProperties = PropertiesService.getScriptProperties();
    var triggerData = JSON.parse(scriptProperties.getProperty(triggerUid));

    var second_sheet = SpreadsheetApp.openById('XXXXXX');
    var second_sheet_page = second_sheet.getSheetByName('StackOverflow');
    var r = 1;
    while (second_sheet_page.getRange(r, 1).getValue()) {
      r++;
    }
    var to_sheet = [
      [triggerData.arguments[0],triggerData.arguments[1],triggerData.arguments[2],triggerData.arguments[3],triggerData.arguments[4]]
    ];
    Utilities.sleep(30000) // I swapped the tasks for a sleep just for testing

    second_sheet_page.getRange(r, 1, to_sheet.length, to_sheet[0].length).setValues(to_sheet);
  } else {
    console.error("Timeout");
  }
  if (!triggerData[RECURRING_KEY]) {
    deleteTriggerByUid(triggerUid);
  }

  return triggerData[ARGUMENTS_KEY];
}

function deleteTriggerArguments(triggerUid) {
  PropertiesService.getScriptProperties().deleteProperty(triggerUid);
}

function deleteTriggerByUid(triggerUid) {
  if (!ScriptApp.getProjectTriggers().some(function(trigger) {
      if (trigger.getUniqueId() === triggerUid) {
        ScriptApp.deleteTrigger(trigger);
        return true;
      }

      return false;
    })) {
    console.error("Could not find trigger with id '%s'", triggerUid);
  }

  deleteTriggerArguments(triggerUid);
}

function deleteTrigger(trigger) {
  ScriptApp.deleteTrigger(trigger);
  deleteTriggerArguments(trigger.getUniqueId());
}

function doGet(e) {
  var trigger = ScriptApp.newTrigger("triggerfunct").timeBased()
    .after(1)
    .create();

  setupTriggerArguments(trigger, [e.parameter.backteam, e.parameter.backodds, e.parameter.layteam, e.parameter.layodds, e.parameter.advantage], false);
}

function triggerfunct(event) {
  var functionArguments = handleTriggered(event.triggerUid);
  console.info("Function arguments: %s", functionArguments);
}

但目前的结果是,除了不考虑发送数据的顺序外,还注意到值是叠加的,而不是放在不同的行上,即使我在文档上放置了锁,这样就不会发生这种情况.

enter image description here

我的预期结果是:

enter image description here

有没有办法解决这些问题?

我真正需要的是通过requests激活GAS中的代码,但我不想等到每次执行完整个代码后,才完成requests.

换句话说,我想在GAS中激活任意次数的代码,必要时生成一个执行队列,然后继续我的生活,而不用担心执行需要多长时间.

例如,在Python中使用subprocessrequests放在后台,我不能这样做,因为它将继续执行,这会显著增加每月的成本,因此我真正需要的是一种完全取消GAS执行与所做请求之间的链接的方法.

为了加快进程,我修改了代码:

var second_sheet = SpreadsheetApp.openById('XXXXXXX');
var second_sheet_page = second_sheet.getSheetByName('STACKTEST');
var r = 1;
while (second_sheet_page.getRange(r, 1).getValue()) {
  r++;
}
second_sheet_page.getRange(r, 1, 1, 5).setValues([[backteam,backodds,layteam,layodds,advantage]]);

至(Enable the Google Sheets API advanced service):

var sheet_id = 'XXXXXXX';
var sheet = SpreadsheetApp.openById(sheet_id);
var sheet_page = sheet.getSheetByName('STACKTEST');
var avals = Sheets.Spreadsheets.Values.get(sheet_id, 'STACKTEST!A1:A').values;
var r = avals.length + 1;
var to_sheet = [
  [triggerData.arguments[0],triggerData.arguments[1],triggerData.arguments[2],triggerData.arguments[3],triggerData.arguments[4]]
];
sheet_page.getRange(r, 1, to_sheet.length, to_sheet[0].length).setValues(to_sheet);

Test reduce time

当填充12800行时,使用第一种方法(因此在第12801行中添加值):

Timeout Error (exceeded the 6 minute runtime limit)

使用Google Sheets API:

804ms

当填充1000行时,使用第一种方法(因此在第1001行中添加值):

3493ms

使用Google Sheets API:

833ms

推荐答案

你可以force a timeout.

调用甚至可能不会激活GAS脚本,因为它将在请求到达之前过期

有两种不同类型的超时:连接和读取.连接超时等待第一次连接.读取超时等待服务器发送数据.将连接超时设置为大于一分钟,但将读取超时设置为小于几秒.

# connect timeout to 60s(to make sure the request is actually sent) and read timeout to 1s
requests.get(webAppsUrl + "?backteam=b1", timeout=(60,1))

很少有理由让一个简单的脚本花费30秒.通过go 掉所有不必要的getValue()个调用并使用数组,可以对代码进行大量优化.见:Long processing time likely due to getValue and cell inserts

值是叠加的,而不是放在不同的线上

这可以通过使用.appendRow而不是setValues()来避免,因为appendRow操作是原子操作.

除了不遵守发送数据的顺序之外

由于进程的异步性质,这是无法避免的.但是,您始终可以稍后根据id重新排列数据.

如果需要,生成一个执行队列,继续我的生活,而不必担心执行需要多长时间.

同时执行限制为30

Python相关问答推荐

如何避免Chained when/then分配中的Mypy不兼容类型警告?

Streamlit应用程序中的Plotly条形图中未正确显示Y轴刻度

启动带有参数的Python NTFS会导致文件路径混乱

为什么np. exp(1000)给出溢出警告,而np. exp(—100000)没有给出下溢警告?

在Python中使用if else或使用regex将二进制数据如111转换为001""

如何在Python中使用Pandas将R s Tukey s HSD表转换为相关矩阵''

如何使用使用来自其他列的值的公式更新一个rabrame列?

基于另一列的GROUP-BY聚合将列添加到Polars LazyFrame

Gunicorn无法启动Flask应用,因为无法将应用解析为属性名或函数调用.'"'' "

如何在Python请求中组合多个适配器?

使用Python异步地持久跟踪用户输入

如何在Python 3.9.6和MacOS Sonoma 14.3.1下安装Pyregion

如何合并具有相同元素的 torch 矩阵的行?

如何反转一个框架中列的值?

为什么dict. items()可以快速查找?

Pandas数据框上的滚动平均值,其中平均值的中心基于另一数据框的时间

类型对象';敌人';没有属性';损害';

按列表分组到新列中

将Pandas DataFrame中的列名的长文本打断/换行为_STRING输出?

日志(log)轴上的自定义刻度出现意外的次要刻度标记行为