如何理解LockService并正确实现?

时间:2017-04-05 06:47:30

标签: google-apps-script locking

代码摘要

我有一个Google Apps脚本项目,特定域内的大约80个用户使用该项目,但该应用程序由我执行(即Publish> Deploy as web app> Execute the app asMe)。

该脚本的一个功能是从自定义表单(使用HTML Service)填充Google表格,然后通知我自己和提交用户(通过使用简单的登录系统和cookie识别出来的用户) )。

它已经工作了大约6个月,但是在1-2次通知电子邮件已经发送但是Google Sheet条目没有出现。

我认为这可能是由于同时使用脚本(因为两个通知电子邮件具有相同的时间戳)并且最近了解到Lock Service

我正在使用此帖子以确保我对Lock及其实施方式有正确的理解,以防止由于并发脚本使用而导致条目未出现在Google表格中。

实施

我的方案的伪代码是:

Code.gs

var active_spreadsheet = SpreadsheetApp.openById("bbb");

// BEGIN - start lock here

var lock = LockService.getScriptLock();
try {
   lock.waitLock(30000); // wait 30 seconds for others' use of the code section and lock to stop and then proceed
 } catch (e) {
   Logger.log('Could not obtain lock after 30 seconds.');
 }

var active_sheet = active_spreadsheet.getSheetByName("ENTRIES");
var new_start_row = active_sheet.getLastRow() + 1;

//  Do lots of stuff - ie apply dynamic background colors based on previous entries colors, define the target range and set values, set data validations  

SpreadsheetApp.flush(); // applies all pending spreadsheet changes
lock.releaseLock();

// END - end lock here

return; 

问题

01) LockServicegetScriptLock()waitLock()releaseLock()的实施是否正确?

02)建议使用SpreadsheetApp.flush(),如果是,那么上述实施是否正确?

术语(供参考)

来自:https://developers.google.com/apps-script/reference/lock

Lock
代表互斥锁。

LockService
阻止对代码段的并发访问。

Lock类有4种方法:

hasLock()
Boolean,如果获取了锁,则返回true。

releaseLock()
void,释放锁定,允许等待锁定的其他进程继续。

tryLock(timeoutInMillis)
布尔值,尝试获取锁定,在提供的毫秒数后超时。

waitLock(timeoutInMillis)
void,尝试获取锁定,在提供的毫秒数后超时超时。

LockService类有3个方法:

getDocumentLock()
Lock,获取一个锁,阻止当前文档的任何用户同时运行一段代码。

getScriptLock()
Lock,获取一个锁,阻止任何用户同时运行一段代码。

getUserLock()
Lock,获取一个锁,阻止当前用户同时运行一段代码。

2 个答案:

答案 0 :(得分:7)

在上面的伪代码中,一旦脚本没有锁定,它仍然会继续运行代码。这是预期的行为吗?向用户抛出服务器忙消息是一种更好的做法或选择。 像这样:

var active_spreadsheet = SpreadsheetApp.openById("bbb");

// BEGIN - start lock here

var lock = LockService.getScriptLock();
try {
    lock.waitLock(30000); // wait 30 seconds for others' use of the code section and lock to stop and then proceed
} catch (e) {
    Logger.log('Could not obtain lock after 30 seconds.');
    return HtmlService.createHtmlOutput("<b> Server Busy please try after some time <p>")
    // In case this a server side code called asynchronously you return a error code and display the appropriate message on the client side
    return "Error: Server busy try again later... Sorry :("
}

// note:  if return is run in the catch block above the following will not run as the function will be exited

var active_sheet = active_spreadsheet.getSheetByName("ENTRIES");
var new_start_row = active_sheet.getLastRow() + 1;

//  Do lots of stuff - ie apply dynamic background colors based on previous entries colors, define the target range and set values, set data validations  

SpreadsheetApp.flush(); // applies all pending spreadsheet changes
lock.releaseLock();

// END - end lock here

return;

希望有所帮助!

答案 1 :(得分:1)

所以我认为我发现锁定系统有问题。也就是说,当您在脚本中触发一个弹出框(出现在工作表中)时,它会取消锁定……或类似的操作,因为它肯定不会保留锁定。我有一段代码要尝试运行,并且基本上没有弹出框,锁定系统也可以运行。没问题,当第一个用户拥有锁时,haslock确实会返回false ...,但是您引入了一个弹出框,锁系统无法正常工作,甚至向第二个用户授予了锁。弹出框和该行代码,或该行之后的任何代码行,都尚未执行。。我在弹出框之后尝试了一段时间,因为我本来以为可能不是在等待输入回来,所以因此,在将弹出框推到工作表后,它只是跳过了弹出框...但是即使在代码的弹出框部分(并且脚本仍在我的脸前运行)后仍存在较长的延迟用户仍被授予锁定。.也许我做错了,但是弹出框是唯一使我的代码无效的东西。我尝试过尝试,抓住了,如果还有,如果...其他没有运气,我什至只是尝试了一个if,else ...我知道这不是因为trylock / waitlock太长或太短我已经尝试了一系列值,我也知道不是我尝试过一系列值以及代码中不同位置的sleep bc。在不列颠哥伦比亚省多个不同日期对不同的Google用户帐户进行了相当严格的测试,我最初认为这只是我的傻瓜之类。.但实际上似乎弹出框是唯一将其从预订中发送出去的东西。 锁定系统何时工作的示例

function myFunction() {
  var lock = LockService.getScriptLock();
  lock.tryLock(5000);
  if (!lock.hasLock()) {
    Logger.log('Could not obtain lock after 5 seconds.');
    return;
  }
  else if (lock.hasLock()) {
    Logger.log('got the lock');
    //Browser.inputBox("TESTING123");
    Utilities.sleep(10000);
  }
lock.releaseLock();
}

2

function myFunction() {
  var lock = LockService.getScriptLock();
  lock.tryLock(5000);
  if (!lock.hasLock()) {
    Logger.log('Could not obtain lock after 5 seconds.');
  }
  else {
    Logger.log('got the lock');
    //Browser.inputBox("TESTING123");
    Utilities.sleep(10000);
  }
lock.releaseLock();
}

使用建议的try,catch语句

function myFunction() {
  var lock = LockService.getScriptLock();
  try {
    lock.waitLock(5000); // wait 5 seconds try to get lock
  } catch (e) {
    Logger.log('Could not obtain lock after 5 seconds.');
  }
  Utilities.sleep(10000);
  //Browser.inputBox("TESTING123");
  lock.releaseLock();
}

它确实捕获了错误并显示了弹出窗口,提示它无法获取

无效的示例

function myFunction() {
  var lock = LockService.getScriptLock();
  lock.tryLock(5000);
  if (!lock.hasLock()) {
    Logger.log('Could not obtain lock after 5 seconds.');
    return;
  }
  else if (lock.hasLock()) {
    Logger.log('got the lock');
    Browser.inputBox("TESTING123");
    Utilities.sleep(10000);
  }
 lock.releaseLock();
}

2

function myFunction() {
  var lock = LockService.getScriptLock();
  lock.tryLock(5000);
  if (!lock.hasLock()) {
    Logger.log('Could not obtain lock after 5 seconds.');
  }
  else {
    Logger.log('got the lock');
    Browser.inputBox("TESTING123");
    Utilities.sleep(10000);
  }
lock.releaseLock();
}

使用建议的try catch语句

function myFunction() {
  var lock = LockService.getScriptLock();
  try {
    lock.waitLock(5000); // wait 5 seconds try to get lock
  } catch (e) {
    Logger.log('Could not obtain lock after 5 seconds.');
  }
  Utilities.sleep(10000);
  Browser.inputBox("TESTING123");
  lock.releaseLock();
}

在所有情况下都会出现弹出框。不应该这样,因为还没有填充并解决弹出框...即使在弹出框行之后添加了延迟。我已决定采用自己的锁定系统,因为google系统似乎不会为我工作,因为我需要锁定在弹出窗口后保持有效。