此代码是否正确锁定onFormSubmit(e)方法?

问题描述 投票:0回答:1

我有一个Google Spreadsheet脚本函数onFormSubmit(e),每当有人提交我的表单时,触发器就会调用该函数。

在函数中,我创建了模板文档的临时副本,并根据提交的表单值在其中进行搜索和替换。然后将该临时副本转换为pdf,并通过电子邮件发送到多个电子邮件地址,然后将其删除。

现在,我已经了解到锁定可能是一个问题,因此我决定获取一个LockService.getScriptLock(),并将我的脚本包装在一个锁中,尝试首先获取30秒的锁lock.waitLock(30000),然后释放该锁。锁定脚本lock.releaseLock()的末尾以防止并发问题。

[有人提交表单时,脚本本身似乎运行时间不会超过13秒。

所以总的来说,代码看起来像这样:

function onFormSubmit(e) {
    // Get a public lock on the script
    var lock = LockService.getScriptLock();
    try {
      lock.waitLock(30000);  // Wait for 30 seconds

      // copy template, search and replace etc...

      lock.releaseLock()

    }catch(e) {
      Logger.log('Could not obtain lock after 30 seconds.');
      MailApp.sendEmail("[email protected]", "Could not obtain lock after 30 seconds.");
    }
}

还有什么我应该做的?我锁得太多还是太少?我记得在Java时代,将全局应用程序会话上下文锁定太长时间是一种罪过。另外,制作模板的副本,然后打开模板的副本以进行搜索和替换,这是否需要某种锁定?

google-apps-script google-sheets locking google-form
1个回答
4
投票
您的锁处理的基本结构还可以,但是您在try..catch中做的太多。请注意,将捕获

any异常,但是您的处理仅限于waitlock()超时异常,因此

您应避免在try块中可能会生成异常的任何其他语句。

以下是您应如何重组功能的方法:function onFormSubmit(e) { // Perform any "pre" operations on private // or non-critical shared resources. var sheet = e.range.getSheet(); // for example, accessing event object // Get a public lock on the script var lock = LockService.getScriptLock(); // Choose appropriate scope try { // just attempt to get the lock here - nothing else that may // throw an exception. lock.waitLock(30000); // Wait for 30 seconds }catch(e) { // Handle lock exception here Logger.log('Could not obtain lock after 30 seconds.'); MailApp.sendEmail("[email protected]", "Could not obtain lock after 30 seconds."); } ////// Critical section begins vvvvv // operate only on shared modifiable data ////// Critical section ends ^^^^^ lock.releaseLock() // Continue with operations on private // or non-critical shared resources. // Ensure the lock is released before exiting. if (lock.hasLock()) { throw new Error("Lock violation"); } else { return; } }

Lock Service提供了一种隔离critical section代码的方法。关键部分是我们控制对必须稳定读取或写入的共享资源的访问。这里的原理可以总结如下:

    尽量不要进入临界区。
可以在临界区之外执行而无需依赖它的任何操作都应事先进行。这不是一成不变的规则,但是根据我的经验,我发现它支持下一个目标的规范,方法是强迫您(或下一个开发人员)预先分析新的代码行是属于内部还是外部。关键部分。
  • 选择适当的锁定范围。这将取决于封装在关键部分中的资源操作的类型。
  • 在关键部分中,请尽快退出。通过仅将自己限制于依赖于“共享的可修改数据”(也称为“关键资源”)的操作,可以达到此目标。
  • 限制关键部分之后执行的操作。
  • 同样,这是一门纪律性的事情。同样,在关键部分之外,我们应该仅管理私有或非关键共享资源。但是在这里,我们进一步限制自己,使其仅依赖于关键部分中发生的操作。我们的目标是在退出关键部分后尽快退出该功能。
  • 释放锁,并仔细检查。
  • 如果从函数返回时不小心将锁留在原处,则只有在执行脚本退出或被杀死时(例如6分钟后),才会释放该锁。这可以通过在releaseLock()hasLock()验证检查之间添加临界区后代码来结束。
  • 我记得在我的Java时代,将全局应用程序会话上下文锁定太长时间是一种罪过...
    在Google Apps脚本中,我们没有这个概念;没有全局应用程序会话。脚本可以异步执行,一个用户可以有多个实例,其他用户可以有多个实例。在这种环境下,关注点转移到仅在

    适当范围

    上锁定,以限制锁定的可能影响。

    ...如何制作模板副本,并打开模板副本进行搜索和替换,这需要某种锁定吗?

    制作模板的副本不需要关键部分,因为我们正在从稳定的共享资源(模板)中读取内容以创建(可能是)私有资源。 (除非模板本身可以被脚本修改。)

      打开该
    • 私有
    • 副本以进行搜索和替换-不重要,不需要锁定。
  • © www.soinside.com 2019 - 2024. All rights reserved.