为什么 LockService 没有按预期工作?
Why is the LockService is not working as intended?
同一个条目开始保存多次时出现问题,我意识到这主要是由双击引起的。我正在尝试使用 LockService 来避免它:如果在毫秒内未获取锁,则应中止脚本(因为它是重复操作)。
//more code above
var lock = LockService.getScriptLock();
try{
lock.waitLock(1);//get the lock timing out in 1 millisecond
SpreadsheetApp.flush();
ss.insertRowBefore(6);
ss.getRange("A6").setValue(data[0][0]);
ss.getRange("B6").setValue(formatedString);
ss.getRange("C6").setValue(data[1][0]);
ss.getRange("D6").setValue(data[2][0]);
ss.getRange("E6").setValue(data[3][0]);
ss.getRange("F6").setValue(data[ref][0]);
SpreadsheetApp.flush();
Utilities.sleep(10);//This is to make sure it takes at least 1 millisecond
}
catch(e){
return;//It should generate a exception and end the script if the lock is not aquired
}
//more code bellow
问题是我仍然收到重复的条目(大多数时候只有 2 个条目,所以我相信它部分起作用了)。我做错了什么?
试试这个方法:
let lock = LockService.getScriptLock();
lock.tryLock(10000);
if (lock.hasLock()) {
ss.insertRowBefore(6);
ss.getRange(6, 1, 1, 6).setValues([data[0][0], formatedString, data[1][0], data[2][0]], data[3][0], data[ref][0])
SpreadsheetApp.flush();
lock.releaseLock();
}
我设法通过添加一个“标志”单元格来计算活动提交的数量来解决我的问题。我只在它周围使用锁。
var rep = ss.getRange("C1");//the flag starting with 0
var lock = LockService.getScriptLock();
try{
lock.waitLock(1000);
var vAtual = rep.getValue();
if(vAtual >= 1)
return;//return hopefully if it already have one active submission
rep.setValue(vAtual+1);//increment for each active submit
SpreadsheetApp.flush();
lock.releaseLock();
}
catch(e){
return;
}
它不是很漂亮,但到目前为止它有效。但是我还是想知道为什么我原来的锁策略失败了。它也可以帮助其他一些有类似问题的人。
根据您的示例 sheet,您在锁定后续代码并清除其内容之前已经读取了单元格中的数据。
您的原始代码:
var data = ss.getRange("B1:B2").getValues();
if(data[0][0] == "" || data[1][0] == "")
return;
var lock = LockService.getScriptLock();
try{
lock.waitLock(1);//get the lock timing out in 1 millisecond
SpreadsheetApp.flush();
ss.insertRowBefore(7);
ss.getRange("A7").setValue(data[0][0]);
ss.getRange("B7").setValue(data[1][0]);
SpreadsheetApp.flush();
Utilities.sleep(10);//This is to make sure it takes at least 1 millisecond
lock.releaseLock();
ss.getRange("B1:B2").setValue("");
}
catch(e){
return;//It should generate a exception and end the script if the lock is not aquired
}
它有什么作用?
- 当你多次点击提交按钮执行你的代码时,它会有n次执行实例。只要清除单元格不生效,每次执行都可以写入从
B1:B2
. 读取的数据
示例:
Execution 1 started at 01:00:00.001 - already read the values in `B1:B2`
Execution 2 started at 01:00:00.005 - already read the values in `B1:B2`
Execution 3 started at 01:00:00.010 - already read the values in `B1:B2`
执行 1 清除了 01:00:00.012 处的 B1:B2
内容。因此,您将拥有提交数据的 3 份副本。使用锁定服务挂起新行中的数据写入,但未锁定要添加的数据的读取。
解决方案
function submit() {
Utilities.sleep(1000);//simulate the upper part of the code
var ss = SpreadsheetApp.getActive().getSheetByName("spr1");
var lock = LockService.getScriptLock();
try{
lock.waitLock(1);//get the lock timing out in 1 millisecond
Logger.log("Locked: "+Utilities.formatDate(new Date(),Session.getScriptTimeZone(),"yyyy-MM-dd'T'HH:mm:ss.SSS"));
var data = ss.getRange("B1:B2").getValues();
Logger.log(data);
if(data[0][0] == "" || data[1][0] == "")
return;
SpreadsheetApp.flush();
ss.insertRowBefore(7);
ss.getRange("A7").setValue(data[0][0]);
ss.getRange("B7").setValue(data[1][0]);
Utilities.sleep(10);//This is to make sure it takes at least 1 millisecond
ss.getRange("B1:B2").setValue("");
SpreadsheetApp.flush();
lock.releaseLock();
Logger.log("UnLocked: "+Utilities.formatDate(new Date(),Session.getScriptTimeZone(),"yyyy-MM-dd'T'HH:mm:ss.SSS"));
}
catch(e){
return;//It should generate a exception and end the script if the lock is not acquired
}
Utilities.sleep(1000);//simulate the lower part of the code
}
完成的更改:
- 先锁定脚本再读取
B1:B2
中的数据
- 确保在使用
flush()
添加到新行后清除 B1:B2
的内容,然后再释放锁定。
输出:
同一个条目开始保存多次时出现问题,我意识到这主要是由双击引起的。我正在尝试使用 LockService 来避免它:如果在毫秒内未获取锁,则应中止脚本(因为它是重复操作)。
//more code above
var lock = LockService.getScriptLock();
try{
lock.waitLock(1);//get the lock timing out in 1 millisecond
SpreadsheetApp.flush();
ss.insertRowBefore(6);
ss.getRange("A6").setValue(data[0][0]);
ss.getRange("B6").setValue(formatedString);
ss.getRange("C6").setValue(data[1][0]);
ss.getRange("D6").setValue(data[2][0]);
ss.getRange("E6").setValue(data[3][0]);
ss.getRange("F6").setValue(data[ref][0]);
SpreadsheetApp.flush();
Utilities.sleep(10);//This is to make sure it takes at least 1 millisecond
}
catch(e){
return;//It should generate a exception and end the script if the lock is not aquired
}
//more code bellow
问题是我仍然收到重复的条目(大多数时候只有 2 个条目,所以我相信它部分起作用了)。我做错了什么?
试试这个方法:
let lock = LockService.getScriptLock();
lock.tryLock(10000);
if (lock.hasLock()) {
ss.insertRowBefore(6);
ss.getRange(6, 1, 1, 6).setValues([data[0][0], formatedString, data[1][0], data[2][0]], data[3][0], data[ref][0])
SpreadsheetApp.flush();
lock.releaseLock();
}
我设法通过添加一个“标志”单元格来计算活动提交的数量来解决我的问题。我只在它周围使用锁。
var rep = ss.getRange("C1");//the flag starting with 0
var lock = LockService.getScriptLock();
try{
lock.waitLock(1000);
var vAtual = rep.getValue();
if(vAtual >= 1)
return;//return hopefully if it already have one active submission
rep.setValue(vAtual+1);//increment for each active submit
SpreadsheetApp.flush();
lock.releaseLock();
}
catch(e){
return;
}
它不是很漂亮,但到目前为止它有效。但是我还是想知道为什么我原来的锁策略失败了。它也可以帮助其他一些有类似问题的人。
根据您的示例 sheet,您在锁定后续代码并清除其内容之前已经读取了单元格中的数据。
您的原始代码:
var data = ss.getRange("B1:B2").getValues();
if(data[0][0] == "" || data[1][0] == "")
return;
var lock = LockService.getScriptLock();
try{
lock.waitLock(1);//get the lock timing out in 1 millisecond
SpreadsheetApp.flush();
ss.insertRowBefore(7);
ss.getRange("A7").setValue(data[0][0]);
ss.getRange("B7").setValue(data[1][0]);
SpreadsheetApp.flush();
Utilities.sleep(10);//This is to make sure it takes at least 1 millisecond
lock.releaseLock();
ss.getRange("B1:B2").setValue("");
}
catch(e){
return;//It should generate a exception and end the script if the lock is not aquired
}
它有什么作用?
- 当你多次点击提交按钮执行你的代码时,它会有n次执行实例。只要清除单元格不生效,每次执行都可以写入从
B1:B2
. 读取的数据
示例:
Execution 1 started at 01:00:00.001 - already read the values in `B1:B2`
Execution 2 started at 01:00:00.005 - already read the values in `B1:B2`
Execution 3 started at 01:00:00.010 - already read the values in `B1:B2`
执行 1 清除了 01:00:00.012 处的 B1:B2
内容。因此,您将拥有提交数据的 3 份副本。使用锁定服务挂起新行中的数据写入,但未锁定要添加的数据的读取。
解决方案
function submit() {
Utilities.sleep(1000);//simulate the upper part of the code
var ss = SpreadsheetApp.getActive().getSheetByName("spr1");
var lock = LockService.getScriptLock();
try{
lock.waitLock(1);//get the lock timing out in 1 millisecond
Logger.log("Locked: "+Utilities.formatDate(new Date(),Session.getScriptTimeZone(),"yyyy-MM-dd'T'HH:mm:ss.SSS"));
var data = ss.getRange("B1:B2").getValues();
Logger.log(data);
if(data[0][0] == "" || data[1][0] == "")
return;
SpreadsheetApp.flush();
ss.insertRowBefore(7);
ss.getRange("A7").setValue(data[0][0]);
ss.getRange("B7").setValue(data[1][0]);
Utilities.sleep(10);//This is to make sure it takes at least 1 millisecond
ss.getRange("B1:B2").setValue("");
SpreadsheetApp.flush();
lock.releaseLock();
Logger.log("UnLocked: "+Utilities.formatDate(new Date(),Session.getScriptTimeZone(),"yyyy-MM-dd'T'HH:mm:ss.SSS"));
}
catch(e){
return;//It should generate a exception and end the script if the lock is not acquired
}
Utilities.sleep(1000);//simulate the lower part of the code
}
完成的更改:
- 先锁定脚本再读取
B1:B2
中的数据
- 确保在使用
flush()
添加到新行后清除B1:B2
的内容,然后再释放锁定。