首页 > 解决方案 > 如何每次在 Google Apps 脚本中正确使用 LockService?

问题描述

我试图避免与LockService我的项目同时进行。

在测试运行中,LockService对我有用,没有任何问题。

但是当我推出我的项目时,有时LockService似乎无法正常工作并覆盖电子表格值。

我使用tryLock()hasLock()方法来获取锁。

function test(array) {
  var lock = LockService.getScriptLock();
  if (lock.tryLock(500)) {
    if (!lock.hasLock()) {
      var message = "Another user is submitting form data. Please try again later.";
      return message;
    }
    var ss = SpreadsheetApp.openById(outputId);
    var sheet = ss.getSheetByName("sheet1");
    var lastRow = sheet.getLastRow() + 1;
    var range = sheet.getRange(lastRow, 1, 1, array[0].length);
    range.setValues(array);
    lock.releaseLock();
  }
  else {
    var message = "Another user is submitting form data. Please try again later.";
    return message;
  }
}

当用户同时提交数据时,我想避免在同一最后一行设置值。但有时它似乎会覆盖最后一行中的值,而其中一个数组的值就消失了。

你能指出我的代码的错误吗?

谢谢你。

标签: google-apps-scriptgoogle-sheetslocking

解决方案


您应该了解 Lock Service 的各种行为。

  • tryLock(milliseconds to Wait)并且waitLock(milliseconds to Wait)非常相似。一个区别是,这waitLock()会引发错误,但tryLock()不会。这意味着您希望程序流程如何工作。您想立即发现错误吗?你不想出错吗?(tryLock() 不会创建和错误)您是否故意想要一个错误?您想要withFailureHandler()在客户端触发的致命错误吗?你想让整个堆栈都失败吗?您是否希望此功能完全停止,但只是此功能失败?您是否希望只有一条线路出现故障,而其余功能继续运行?

在您的情况下,让函数中的其余行运行毫无意义。

如果你使用waitLock(milliseconds to Wait)那么你应该有一些东西来捕捉错误。您的选择是:

  • 捕捉该行的错误
  • 在该函数的任何地方捕获错误
  • 不要捕获该函数中的错误

在您的情况下,您不希望函数的其余部分运行。

将错误隔离到一行的一个原因是允许其余代码运行,因为其余代码的结果仍然可以为用户提供一些有用的输出。但这不是你的情况。运行该函数的其余部分,不会为用户提供额外的价值。

事实上,如果你的函数的任何部分失败了,那么它应该停止运行。出于这个原因,我会将函数中的所有行都包装在 try/catch 中。

如果 line:var lock = LockService.getScriptLock();失败了怎么办?

如果该行失败,则lock. 如果没有值,lock则无法释放锁。如果var lock = LockService.getScriptLock();失败,lock.releaseLock();则将失败。

这就是我使用的原因:

LockService.getScriptLock().releaseLock();

这就是为什么我不使用变量来锁定。

有两种情况应该释放锁。

  • 代码成功完成
  • 代码失败

如果在获取锁时代码失败,那么您不希望在释放锁之前让代码等待超时到期。如果到期时间不是很长,那么它可能不是什么大问题。但是如果锁的等待时间长了,那就没有什么好的目的了。如果您的等待时间很短,那么在服务器运行缓慢的情况下,您将面临在代码完成之前锁定到期的风险。所以,我会给你的等待时间一点点填充,但不要太极端。如果您的锁被正确释放,那么等待时间比您需要的时间长一点应该不会产生任何不良影响。如果在很长的等待时间内获得了锁,但不知何故没有被释放,这与没有获得锁一样大。

function myLockFunction() {
try{
  //Your entire code inside the try block
  LockService.getScriptLock().waitLock(milliseconds);//Throws exception if fail

}catch(e){
  LockService.getScriptLock().releaseLock();

}
}

推荐阅读