防止"太多的同时调用"在表格上提交

时间:2015-04-15 18:45:50

标签: google-apps-script google-sheets google-form

目前,我们有一个自动上传的Google表单,并以~50个表单的分期付款。它们会进入电子表格,需要通过订阅onFormSubmit event的触发器来执行操作。

问题在于,由于这些都是同时上传的,因此事件会快速反复发出并发出以下任一警告:

  

同时调用太多:电子表格(第16行,文件"代码")
  很抱歉,发生了服务器错误。请稍等一下再试一次。 (第12行,文件"代码")

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

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

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

:是否有批处理表单提交触发器?

2 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:1)

您可以使用类FormTriggerBuilder来动态创建和销毁触发器。您可以使用PropertiesService保留已创建触发器的ID,然后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。在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
}