【问题标题】:How to understand LockService and implement it correctly?如何理解LockService并正确实现?
【发布时间】:2017-04-05 06:47:30
【问题描述】:

代码摘要

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

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

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

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

我使用这篇文章来确保我对Lock 以及如何实现它有正确的理解,以防止由于并发脚本使用而导致条目没有出现在 Google 表格中。

实施

我的场景的伪代码是:

代码.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()
布尔值,如果获得锁则返回真。

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

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

waitLock(timeoutInMillis)
void, 尝试获取锁,在提供的毫秒数后超时并出现异常。

LockService 类有 3 个方法:

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

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

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

【问题讨论】:

  • 你忽略了锁异常。错了。

标签: google-apps-script locking


【解决方案1】:

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

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;

【讨论】:

  • 那么异常中的 Return 会阻止函数的其余部分完成的逻辑是什么?你介意包括原始帖子中的所有代码,以便我可以确定它们是如何组合在一起的吗?谢谢你。 PS不,如果有另一个代码实例正在运行,我不希望代码继续运行,因此想要实现锁定的原因,我希望它等待然后继续。
  • 没错。 Return,转义函数并终止函数。
  • 非常感谢这个例子!我遇到了同样的问题并且正在摆弄 scriptlock 但没有返回它只是按顺序运行而不是使新脚本失败。
【解决方案2】:

所以我认为我发现了锁定系统的问题。也就是说,当您在脚本中触发一个弹出框(出现在工作表中)时,它会取消锁定...或类似的东西,因为它肯定不会保留锁定。我有一段代码我正在尝试运行,基本上没有弹出框,锁定系统工作。没有问题,当第一个用户拥有锁时,haslock 确实会返回 false ......但是随后您引入了一个弹出框,并且锁定系统无法正常工作,并且即使授予第二个用户锁定也是如此弹出框和那行代码,或者它之后的任何代码行,都没有被执行。我在弹出框之后延迟尝试了它,因为我最初认为它可能没有等待输入回来所以因此,它只是在将弹出框推到工作表后跳过了弹出框......但即使在代码的弹出框部分之后有很长的延迟(并且脚本仍在我面前运行)第二个用户仍然被授予锁..也许我做错了,但弹出框是唯一让我的代码失效的东西。我尝试了 try、catch 和 if、if else ... 没有运气,我什至只尝试了 if、else ... 我知道这不是因为 trylock/waitlock 太长,或者我太短了尝试了一系列值,我也知道这不是 sleep bc 我尝试了一系列值,以及我的代码中的不同位置。在公元前多个不同的日子在不同的谷歌用户帐户上对这些进行了大量测试,我最初认为这是我只是愚蠢之类的......但它真的只是似乎弹出框是唯一将它发送出去的东西...... 锁定系统何时工作的示例

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();
}

在所有情况下都会出现弹出框。它不应该,因为弹出框还没有被填写和解决......即使在弹出框行之后放置了延迟。我决定制作我自己的锁定系统,因为我需要在弹出窗口后保持有效的锁,谷歌系统似乎不会为我工作。

【讨论】:

  • 虽然这篇文章似乎包含一个有效的开发问题,但它本身更适合作为一个问题。我建议将您的帖子复制到一个新问题中,从此处将其删除,并在与您的问题相关时引用此问题。在您的问题中使用标准部分也可能有助于回答:期望的行为、实际行为以及我尝试过的内容。
  • 我同意。好像我们是在一个问题中提出一个问题。
猜你喜欢
  • 1970-01-01
  • 2016-02-14
  • 1970-01-01
  • 2022-08-22
  • 1970-01-01
  • 1970-01-01
  • 2022-01-05
  • 2015-02-27
  • 2013-07-22
相关资源
最近更新 更多