代码摘要
我有一个Google Apps脚本项目,特定域内的大约80个用户使用该项目,但该应用程序由我执行(即Publish
> Deploy as web app
> Execute the app as
:Me
)。
该脚本的一个功能是从自定义表单(使用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) LockService
,getScriptLock()
,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,获取一个锁,阻止当前用户同时运行一段代码。
答案 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系统似乎不会为我工作,因为我需要锁定在弹出窗口后保持有效。