在 formSubmit 上阻止 "Too many simultaneous invocations"

Prevent "Too many simultaneous invocations" on formSubmit

目前我们有一个 Google 表格自动上传并以约 50 个表格的分期批处理。这些进入电子表格,需要由订阅 onFormSubmit event.

的触发器进行操作

问题在于,由于这些都是同时上传的,因此事件会快速连续触发并出现以下警告之一:

Too many simultaneous invocations: Spreadsheets (line 16, file "Code")
We're sorry, a server error occurred. Please wait a bit and try again. (line 12, file "Code")

根据 Daily Quotas Limit,每天最多有 20 个脚本触发器。

这是一个非常合理的数字,只要我能找到一种方法 运行 在最后对所有 50 个背靠背表单提交进行一次触发。

如果我可以为执行设置一个超时以等待并查看在接下来的几秒钟内是否触发了任何其他事件,那就太好了,但是我需要在触发处理程序内部时我' m 正在执行触发器。

: 有没有批量提交表单的触发器?

问题是您似乎正在创建一个触发器来处理每个表单提交。如果处理程序简短而简单,那么就在 onFormSubmit 上执行它。如果这会导致问题,请使用一个触发器,每 10 分钟 运行s 并通过记住最后处理的行并直接从电子表格读取新行来检查是否有工作要做。我说 10 分钟,这样一个触发实例就不会与下一个重叠。如果您使用较短的触发器,请确保不能 运行 与锁平行的部件。

您可以像这样使用 class FormTriggerBuilder to dynamically create and destroy triggers. You can use the PropertiesService to persist the id for the created trigger and then programmatically delete it later

var formID = 'XXXXXXX';
var properties = PropertiesService.getScriptProperties()

function onInstall() {
  createSubmitHandler()
}

function createSubmitHandler() {
 var form = FormApp.openById(formID);
 var trigger = ScriptApp.newTrigger('onSubmit')
     .forForm(form)
     .onFormSubmit()
     .create();

  properties.setProperty('triggerID', trigger.getUniqueId())
}

function destroySubmitHandler() {
   var triggerID = properties.getProperty('triggerID')
   var form = FormApp.openById(formID);
   var allTriggers = ScriptApp.getUserTriggers(form)
   for (var i = 0; i < allTriggers.length; i++) {
     if (allTriggers[i].getUniqueId() == triggerID) {
       ScriptApp.deleteTrigger(allTriggers[i]);
       break;
     }
   }
}

function onSubmit() {
  // we've been called, remove trigger, set timeout, re-enable, and then run function
  destroySubmitHandler();
  Utilities.sleep(5 * 1000)
  createSubmitHandler();
  myFunction()
}

function myFunction() {
  // do stuff here
}

或者,正如 ScampMichael 指出的那样,您可以使用 Lock Service. There's a great write up of it in this article on Concurrency and Google Apps Script。但是,我不确定这就是我想要的。锁定服务会将等待执行的代码排队。这解决了并发执行的问题,但没有达到每个脚本仅 20 个触发器的每日配额的问题,具体取决于配额是如何衡量的。

这是一个如何使用锁定脚本来防止并发调用的示例:

function onSubmit() {
  // we've been called, get a public lock, wait for other job to finish, run the function, and release the cracken
  var lock = LockService.getScriptLock();
  lock.tryLock(30 * 1000);
  myFunction();
  lock.releaseLock();
}

function myFunction() {
  // do stuff here
}