我有一个Google Spreadsheet脚本函数onFormSubmit(e)
,每当有人提交我的表单时,触发器就会调用该函数。
在函数中,我创建了模板文档的临时副本,并根据提交的表单值在其中进行搜索和替换。然后将该临时副本转换为pdf,并通过电子邮件发送到多个电子邮件地址,然后将其删除。
现在,我已经了解到锁定可能是一个问题,因此我决定获取一个LockService.getScriptLock()
,并将我的脚本包装在一个锁中,尝试首先获取30秒的锁lock.waitLock(30000)
,然后释放该锁。锁定脚本lock.releaseLock()
的末尾以防止并发问题。
[有人提交表单时,脚本本身似乎运行时间不会超过13秒。
所以总的来说,代码看起来像这样:
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("[email protected]", "Could not obtain lock after 30 seconds.");
}
}
还有什么我应该做的?我锁得太多还是太少?我记得在Java时代,将全局应用程序会话上下文锁定太长时间是一种罪过。另外,制作模板的副本,然后打开模板的副本以进行搜索和替换,这是否需要某种锁定?
try..catch
中做的太多。请注意,将捕获any异常,但是您的处理仅限于waitlock()
超时异常,因此
您应避免在try
块中可能会生成异常的任何其他语句。
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("[email protected]", "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;
}
}
Lock Service提供了一种隔离critical section代码的方法。关键部分是我们控制对必须稳定读取或写入的共享资源的访问。这里的原理可以总结如下:
releaseLock()
和hasLock()
验证检查之间添加临界区后代码来结束。在Google Apps脚本中,我们没有这个概念;没有全局应用程序会话。脚本可以异步执行,一个用户可以有多个实例,其他用户可以有多个实例。在这种环境下,关注点转移到仅在上锁定,以限制锁定的可能影响。适当范围
...如何制作模板副本,并打开模板副本进行搜索和替换,这需要某种锁定吗?
制作模板的副本不需要关键部分,因为我们正在从稳定的共享资源(模板)中读取内容以创建(可能是)私有资源。 (除非模板本身可以被脚本修改。)