触发根据其创建维护激活顺序并在每次运行中保护电子表格数据

发布于 2025-02-12 20:23:08 字数 6027 浏览 0 评论 0 原文

我将5个请求发送到我的Web应用程序:

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
  }
}

因为我不想等待每个请求完成执行(因为它每个都需要超过30秒的时间,我不在执行期间和之后发生什么),我为每个请求创建一个触发器:

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);
}

但是当前的结果,除了不尊重发送的数据的顺序外,注意到值是叠加而不是放置在不同的线条,即使我已经在文档上锁定了一个锁,以免发生这种情况。

我的预期结果是:

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

我的真正需求是通过请求激活煤气中的代码,但我不想等待整个代码的每个执行的结束,以便 requests 具有已完成。

换句话说,我想在需要的情况下多次激活我的代码,并在必要时产生执行队列,并继续我的生活,而不必担心执行需要多长时间。

使用请求在Python的背景中使用 subprocess 例如我不能,因为它将继续执行,这大大增加了每月的成本,所以我真正需要的是通过提出的请求,一种完全违反了气体执行的方法。

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

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]]);

t​​o():

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);

当填充12800行时,使用第一种方法测试时间减少时间

(因此,将值添加为行12801):

Timeout Error (exceeded the 6 minute runtime limit)

使用Google表API:

804ms

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

3493ms

使用Google Sheeps API:

833ms

I'm sending 5 requests to my Web App:

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)

If I could wait for each of the requests to execute, I could just leave my Web App like this:

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
  }
}

As I don't want to wait for each request to finish executing (because it takes more than 30 seconds each and I don't care what happens during and after the execution), I'm creating a trigger for each request:

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);
}

But the current result, in addition to not respecting the sequence of the data sent, it is noticed that values are superimposed instead of being placed on different lines, even though I have placed a lock on the document so that this does not happen.

enter image description here

My expected result is this:

enter image description here

Is there a way to solve these problems?

My real need is to activate the code in GAS via requests, but I don't want to wait for the end of each execution of the entire code so that the requests has been completed.

In other words, I want to activate my code in GAS as many times as I want, generating a queue of executions if necessary, and go on with my life without worrying about how long it will take to execute.

Putting requests in the background in Python using subprocess for example I can't because it would continue to be executed and this significantly increases the monthly cost, so what I really need is a way to totally unlink the execution of the GAS with the request made.

To speed up the process I modified the code:

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]]);

To (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

Using the first method when 12800 rows filled (so add the values in row 12801):

Timeout Error (exceeded the 6 minute runtime limit)

Using Google Sheets API:

804ms

Using the first method when 1000 rows filled (so add the values in row 1001):

3493ms

Using Google Sheets API:

833ms

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

恍梦境° 2025-02-19 20:23:08

python

您可以强制a超时

呼叫甚至可能无法激活加油脚本,因为它将在请求到达之前过期

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

# 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))

google-apps-scripts

很少有一个简单的脚本需要30秒的原因。可以通过取出所有不必要的 getValue()调用并使用数组来优化您的代码。请参阅:可能是由于GetValue和cell Value和cell inserts造成的长时间处理时间

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

这可以通过使用 .appendrow 而不是 setValues(),因为Appendrow操作是原子。

不尊重发送的数据序列

由于该过程的异步性质,因此无法避免。但是,您始终可以根据ID重新排列数据。

如有必要,生成执行队列,并继续我的生活,而不必担心执行需要多长时间。

同时执行限制为30

You can force a timeout.

the call may not even activate the GAS script because it will expire before the request arrives

There are two different types of timeout: Connect and read. Connect timeout waits for the first connection. Read timeout waits for the data to be sent by the server. Set the connect timeout to larger than a minute, but the read timeout to less than a few seconds.

# 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))

There's rarely reason for a simple script to take 30 seconds. Your code can be optimized a lot by taking out all unnecessary getValue() calls and using arrays. See: Long processing time likely due to getValue and cell inserts

values are superimposed instead of being placed on different lines

This can be avoided by using .appendRow instead of setValues() as appendRow operation is atomic.

in addition to not respecting the sequence of the data sent

This cannot be avoided due to the async nature of the process. But, you can always rearrange the data later based on the id.

generating a queue of executions if necessary, and go on with my life without worrying about how long it will take to execute.

There's a simultaneous execution limit of 30

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文