此代码是否正确锁定onFormSubmit(e)方法? [英] Does this code lock the onFormSubmit(e) method correctly?

查看:84
本文介绍了此代码是否正确锁定onFormSubmit(e)方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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



现在我已经读到锁定可能是个问题在这里,所以我决定得到一个 LockService.getScriptLock(),并将我的脚本封装在一个锁中,首先获得一个锁定30秒 lock.waitLock(30000),然后释放脚本 lock.releaseLock()末尾的锁以防止出现并发问题。

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



所以总之,代码看起来有点像这样:

 函数onFormSubmit(e){
//获取脚本上的公共锁
var lock = LockService.getScriptLock();
尝试{
lock.waitLock(30000); //等待30秒

//复制模板,搜索并替换等...

lock.releaseLock()

} catch( e){
Logger.log('30秒后无法获得锁定。
MailApp.sendEmail(admin@something.com,30秒后无法获得锁定。);
}
}

还有什么我应该做的?我是锁定太多还是太少?我记得在我的Java日子里,将全局应用程序会话上下文锁定时间太长是一种罪过;还有如何做一个模板的副本,并打开模板的副本搜索和替换,这是否需要某种形式的锁定?

解决方案

div>

通过您所描述的性能时序,您可能会发现您可以脱离所展示的功能。至少,直到那天由于力量超出你的控制需要很长的时间。



你的锁定处理的基本结构是可以的,但你也在做很多都在 try..catch 内。请注意,任何 异常都会被捕获,但您的处理仅限于 waitlock()超时异常,所以您应该避免任何其他异常可能会在 try 块中产生异常的语句。



以下是您应如何重构函数的方法:

function onFormSubmit(e){
//执行任何预先私人
//或非关键共享资源上的操作。
var sheet = e.range.getSheet(); //例如,访问事件对象

//获取脚本上的公共锁
var lock = LockService.getScriptLock(); //选择适当的作用域
尝试{
//只是尝试获取锁定 - 没有其他的可能
//抛出一个异常。
lock.waitLock(30000); //等待30秒
} catch(e){
//在此处理锁定异常
Logger.log('30秒后无法获得锁定。
MailApp.sendEmail(admin@something.com,30秒后无法获得锁定。);
}

//////关键部分开始vvvvv

//仅对共享可修改数据操作

/// ///关键部分结束^^^^^
lock.releaseLock()

//继续对私有
//或非关键共享资源进行操作。

//确保在退出之前释放锁。
if(lock.hasLock()){
throw new Error(Lock violation);
}
else {
return;


锁定服务提供了一种方法来隔离代码的关键部分。关键部分是我们控制访问共享资源的位置,这些共享资源在阅读或写作时必须稳定。这里的原则可以概括如下:


  • 尽可能延迟进入临界区。可以在关键部分之外进行,而不依赖于它应该事先完成。这不是一个困难&快速的规则,但根据我的经验,我发现它支持下一个目标的规范,通过强迫你(或下一个开发人员)预先分析一行新代码是否属于关键部分。 li>
  • 为锁定选择合适的范围。这取决于封装在临界区域中的资源操作类型。

  • 进入关键部分后,尽快脱身。通过将自己限制为依赖于共享可修改数据(也称为关键资源)的操作来实现此目标。

  • 限制在关键部分之后执行的操作。再一次,这是一项纪律事情。在关键部分之外,我们只应该再次管理私有或非关键共享资源。但是我们在这里进一步限制自己,只对那些依赖于关键部分发生的事情进行操作。我们的目标是尽快退出该功能,一旦我们退出了关键部分。

  • 释放锁定,然后仔细检查。
  • strong>如果我们在从函数返回时不小心留下锁定,它只会在正在执行的脚本退出或被杀死时释放(例如,6分钟后)。这是通过完成我们的 releaseLock() hasLock()之间的后关键代码来完成的。验证检查。



我记得在Java日子里,锁定全局应用程序会话上下文是一种罪过太久...


在Google Apps脚本中,我们没有这个概念;没有全球应用程序会话。脚本可以异步执行,可以为用户提供多个实例,也可以为其他用户提供实例。在此环境中,问题转移到仅锁定适当范围,以限制锁的可能影响。

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





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

  • 打开私人副本进行搜索和放大替换 - 不重要,不需要锁。


I have a Google Spreadsheet script function onFormSubmit(e) that is called by a trigger whenever someone submits my form.

Within the function I create a temporary copy of a template document and search and replace in it based on the submitted form values. Then that temporary copy is converted to a pdf and emailed to several email addresses, and then deleted.

Now I've read that locking may be an issue here, and so I decided to get a LockService.getScriptLock(), and wrap my script in a lock trying first to obtain a lock for 30 seconds lock.waitLock(30000), and then releasing the lock at the end of the script lock.releaseLock() to prevent concurrency issues.

When someone submits a form, the script itself never seems to run for more than 13 seconds.

So in summary the code looks a bit like this:

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("admin@something.com", "Could not obtain lock after 30 seconds.");
    }
}

Is there anything else I should be doing? Am I locking too much or too little? I remember in my Java days it was a sin to lock the global application session context for too long; also what about making a copy of the template, and opening the copy of the template for search and replace, does that require some sort of locking?

解决方案

With the performance timings that you've described, you will probably find that you can get away with the function you've shown. At least, until that day when the processing takes extra long because of forces out of your control.

The basic structure of your lock handling is OK, but you are doing too much inside the try..catch. Note that any exception will be caught, but your handling is limited to a waitlock() timeout exception, so you should avoid any other statements that may generate exceptions in the try block.

Here's how you should restructure your function:

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("admin@something.com", "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;
  } 
}

The Lock Service provides a way to fence off a critical section of code. A critical section is where we control access to shared resources that must be stable for reading or writing. The principle here can be summarized thus:

  • Defer entering a critical section as long as possible. Any operation that can be performed outside of the critical section without depending on it should be done beforehand. This isn't a hard & fast rule, but in my experience I've found it supports the discipline of the next goal, by forcing you (or the next developer) to analyze up front whether a new line of code belongs in or out of the critical section.
  • Choose the appropriate scope for the lock. This will depend on the type of resource operations encapsulated in the critical section.
  • Once in the critical section, get out ASAP. This goal is served by limiting yourself only to operations that depend on "shared modifiable data", also referred to as "critical resources".
  • Limit the operations performed after the critical section. Again, this is a discipline thing. Outside of the critical section, we should only manage private or non-critical shared resources, again. But here we limit ourselves further, to only operations that are dependent on what happened in the critical section. Our goal here is to get out of the function as quickly as we can, once we've exited the critical section.
  • Release the lock, and double-check. If we accidentally leave a lock in place when returning from a function, it will only be released when the executing script exits or is killed (e.g. after 6 minutes). This is accomplished by book-ending the post-critical-section code between our releaseLock() and a hasLock() validation check.

I remember in my Java days it was a sin to lock the global application session context for too long...

In Google Apps Script, we don't have that concept; there is no global application session. Scripts may be executed asynchronously, with the possibility of multiple instances for a user as well as instances for other users. In this environment, the concern shifts to locking only at the appropriate scope, to limit the possible impact of the lock.

...what about making a copy of the template, and opening the copy of the template for search and replace, does that require some sort of locking?

  • Making a copy of a template doesn't require a critical section because we're reading from a stable shared resource (the template) to create a (presumably) private resource. (Unless the template itself can be modified by the script.)
  • Opening that private copy for search & replace - not critical, no need for a lock.

这篇关于此代码是否正确锁定onFormSubmit(e)方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆