我将5个请求发送到我的Web应用程序:
import requests
backodds = "3.00"
layteam = "Flamengo"
layodds = "1.50"
advantage = "25.55"
webAppsUrl = "https://script.google.com/macros/s/XXXX/exec"
for i in range(5):
requests.get(webAppsUrl + "?backteam=" + str(i) + "&backodds=" + backodds + "&layteam=" + layteam + "&layodds=" + layodds + "&advantage=" + advantage)
如果我可以等待执行的每个请求,那么我可以像这样离开我的Web应用程序:
function doGet(e) {
const lock = LockService.getDocumentLock();
if (lock.tryLock(360000)) {
try {
var backteam = e.parameter.backteam;
var backodds = e.parameter.backodds;
var layteam = e.parameter.layteam;
var layodds = e.parameter.layodds;
var advantage = e.parameter.advantage;
Utilities.sleep(30000) // I swapped the tasks for a sleep just for testing
var second_sheet = SpreadsheetApp.openById('XXXXXXX');
var second_sheet_page = second_sheet.getSheetByName('STACKTEST');
var r = 1;
while (second_sheet_page.getRange(r, 1).getValue()) {
r++;
}
second_sheet_page.getRange(r, 1, 1, 5).setValues([[backteam,backodds,layteam,layodds,advantage]]);
} catch (e) {
//pass
} finally {
lock.releaseLock();
}
} else {
//pass
}
}
因为我不想等待每个请求完成执行(因为它每个都需要超过30秒的时间,我不在执行期间和之后发生什么),我为每个请求创建一个触发器:
var RECURRING_KEY = "recurring";
var ARGUMENTS_KEY = "arguments";
function setupTriggerArguments(trigger, functionArguments, recurring) {
var triggerUid = trigger.getUniqueId();
var triggerData = {};
triggerData[RECURRING_KEY] = recurring;
triggerData[ARGUMENTS_KEY] = functionArguments;
PropertiesService.getScriptProperties().setProperty(triggerUid, JSON.stringify(triggerData));
}
function handleTriggered(triggerUid) {
const lock = LockService.getDocumentLock();
if (lock.tryLock(360000)) {
var scriptProperties = PropertiesService.getScriptProperties();
var triggerData = JSON.parse(scriptProperties.getProperty(triggerUid));
var second_sheet = SpreadsheetApp.openById('XXXXXX');
var second_sheet_page = second_sheet.getSheetByName('StackOverflow');
var r = 1;
while (second_sheet_page.getRange(r, 1).getValue()) {
r++;
}
var to_sheet = [
[triggerData.arguments[0],triggerData.arguments[1],triggerData.arguments[2],triggerData.arguments[3],triggerData.arguments[4]]
];
Utilities.sleep(30000) // I swapped the tasks for a sleep just for testing
second_sheet_page.getRange(r, 1, to_sheet.length, to_sheet[0].length).setValues(to_sheet);
} else {
console.error("Timeout");
}
if (!triggerData[RECURRING_KEY]) {
deleteTriggerByUid(triggerUid);
}
return triggerData[ARGUMENTS_KEY];
}
function deleteTriggerArguments(triggerUid) {
PropertiesService.getScriptProperties().deleteProperty(triggerUid);
}
function deleteTriggerByUid(triggerUid) {
if (!ScriptApp.getProjectTriggers().some(function(trigger) {
if (trigger.getUniqueId() === triggerUid) {
ScriptApp.deleteTrigger(trigger);
return true;
}
return false;
})) {
console.error("Could not find trigger with id '%s'", triggerUid);
}
deleteTriggerArguments(triggerUid);
}
function deleteTrigger(trigger) {
ScriptApp.deleteTrigger(trigger);
deleteTriggerArguments(trigger.getUniqueId());
}
function doGet(e) {
var trigger = ScriptApp.newTrigger("triggerfunct").timeBased()
.after(1)
.create();
setupTriggerArguments(trigger, [e.parameter.backteam, e.parameter.backodds, e.parameter.layteam, e.parameter.layodds, e.parameter.advantage], false);
}
function triggerfunct(event) {
var functionArguments = handleTriggered(event.triggerUid);
console.info("Function arguments: %s", functionArguments);
}
但是当前的结果,除了不尊重发送的数据的顺序外,注意到值是叠加而不是放置在不同的线条,即使我已经在文档上锁定了一个锁,以免发生这种情况。
我的预期结果是:
有没有办法解决这些问题?
我的真正需求是通过请求
激活煤气中的代码,但我不想等待整个代码的每个执行的结束,以便 requests
具有已完成。
换句话说,我想在需要的情况下多次激活我的代码,并在必要时产生执行队列,并继续我的生活,而不必担心执行需要多长时间。
使用请求
在Python的背景中使用 subprocess
例如我不能,因为它将继续执行,这大大增加了每月的成本,所以我真正需要的是通过提出的请求,一种完全违反了气体执行的方法。
为了加快进程的速度,我修改了代码:
var second_sheet = SpreadsheetApp.openById('XXXXXXX');
var second_sheet_page = second_sheet.getSheetByName('STACKTEST');
var r = 1;
while (second_sheet_page.getRange(r, 1).getValue()) {
r++;
}
second_sheet_page.getRange(r, 1, 1, 5).setValues([[backteam,backodds,layteam,layodds,advantage]]);
to():
var sheet_id = 'XXXXXXX';
var sheet = SpreadsheetApp.openById(sheet_id);
var sheet_page = sheet.getSheetByName('STACKTEST');
var avals = Sheets.Spreadsheets.Values.get(sheet_id, 'STACKTEST!A1:A').values;
var r = avals.length + 1;
var to_sheet = [
[triggerData.arguments[0],triggerData.arguments[1],triggerData.arguments[2],triggerData.arguments[3],triggerData.arguments[4]]
];
sheet_page.getRange(r, 1, to_sheet.length, to_sheet[0].length).setValues(to_sheet);
当填充12800行时,使用第一种方法测试时间减少时间
(因此,将值添加为行12801):
Timeout Error (exceeded the 6 minute runtime limit)
使用Google表API:
804ms
填充1000行时使用第一种方法(因此在第1001行中添加值):
3493ms
使用Google Sheeps API:
833ms
I'm sending 5 requests to my Web App:
import requests
backodds = "3.00"
layteam = "Flamengo"
layodds = "1.50"
advantage = "25.55"
webAppsUrl = "https://script.google.com/macros/s/XXXX/exec"
for i in range(5):
requests.get(webAppsUrl + "?backteam=" + str(i) + "&backodds=" + backodds + "&layteam=" + layteam + "&layodds=" + layodds + "&advantage=" + advantage)
If I could wait for each of the requests to execute, I could just leave my Web App like this:
function doGet(e) {
const lock = LockService.getDocumentLock();
if (lock.tryLock(360000)) {
try {
var backteam = e.parameter.backteam;
var backodds = e.parameter.backodds;
var layteam = e.parameter.layteam;
var layodds = e.parameter.layodds;
var advantage = e.parameter.advantage;
Utilities.sleep(30000) // I swapped the tasks for a sleep just for testing
var second_sheet = SpreadsheetApp.openById('XXXXXXX');
var second_sheet_page = second_sheet.getSheetByName('STACKTEST');
var r = 1;
while (second_sheet_page.getRange(r, 1).getValue()) {
r++;
}
second_sheet_page.getRange(r, 1, 1, 5).setValues([[backteam,backodds,layteam,layodds,advantage]]);
} catch (e) {
//pass
} finally {
lock.releaseLock();
}
} else {
//pass
}
}
As I don't want to wait for each request to finish executing (because it takes more than 30 seconds each and I don't care what happens during and after the execution), I'm creating a trigger for each request:
var RECURRING_KEY = "recurring";
var ARGUMENTS_KEY = "arguments";
function setupTriggerArguments(trigger, functionArguments, recurring) {
var triggerUid = trigger.getUniqueId();
var triggerData = {};
triggerData[RECURRING_KEY] = recurring;
triggerData[ARGUMENTS_KEY] = functionArguments;
PropertiesService.getScriptProperties().setProperty(triggerUid, JSON.stringify(triggerData));
}
function handleTriggered(triggerUid) {
const lock = LockService.getDocumentLock();
if (lock.tryLock(360000)) {
var scriptProperties = PropertiesService.getScriptProperties();
var triggerData = JSON.parse(scriptProperties.getProperty(triggerUid));
var second_sheet = SpreadsheetApp.openById('XXXXXX');
var second_sheet_page = second_sheet.getSheetByName('StackOverflow');
var r = 1;
while (second_sheet_page.getRange(r, 1).getValue()) {
r++;
}
var to_sheet = [
[triggerData.arguments[0],triggerData.arguments[1],triggerData.arguments[2],triggerData.arguments[3],triggerData.arguments[4]]
];
Utilities.sleep(30000) // I swapped the tasks for a sleep just for testing
second_sheet_page.getRange(r, 1, to_sheet.length, to_sheet[0].length).setValues(to_sheet);
} else {
console.error("Timeout");
}
if (!triggerData[RECURRING_KEY]) {
deleteTriggerByUid(triggerUid);
}
return triggerData[ARGUMENTS_KEY];
}
function deleteTriggerArguments(triggerUid) {
PropertiesService.getScriptProperties().deleteProperty(triggerUid);
}
function deleteTriggerByUid(triggerUid) {
if (!ScriptApp.getProjectTriggers().some(function(trigger) {
if (trigger.getUniqueId() === triggerUid) {
ScriptApp.deleteTrigger(trigger);
return true;
}
return false;
})) {
console.error("Could not find trigger with id '%s'", triggerUid);
}
deleteTriggerArguments(triggerUid);
}
function deleteTrigger(trigger) {
ScriptApp.deleteTrigger(trigger);
deleteTriggerArguments(trigger.getUniqueId());
}
function doGet(e) {
var trigger = ScriptApp.newTrigger("triggerfunct").timeBased()
.after(1)
.create();
setupTriggerArguments(trigger, [e.parameter.backteam, e.parameter.backodds, e.parameter.layteam, e.parameter.layodds, e.parameter.advantage], false);
}
function triggerfunct(event) {
var functionArguments = handleTriggered(event.triggerUid);
console.info("Function arguments: %s", functionArguments);
}
But the current result, in addition to not respecting the sequence of the data sent, it is noticed that values are superimposed instead of being placed on different lines, even though I have placed a lock on the document so that this does not happen.

My expected result is this:

Is there a way to solve these problems?
My real need is to activate the code in GAS via requests
, but I don't want to wait for the end of each execution of the entire code so that the requests
has been completed.
In other words, I want to activate my code in GAS as many times as I want, generating a queue of executions if necessary, and go on with my life without worrying about how long it will take to execute.
Putting requests
in the background in Python using subprocess
for example I can't because it would continue to be executed and this significantly increases the monthly cost, so what I really need is a way to totally unlink the execution of the GAS with the request made.
To speed up the process I modified the code:
var second_sheet = SpreadsheetApp.openById('XXXXXXX');
var second_sheet_page = second_sheet.getSheetByName('STACKTEST');
var r = 1;
while (second_sheet_page.getRange(r, 1).getValue()) {
r++;
}
second_sheet_page.getRange(r, 1, 1, 5).setValues([[backteam,backodds,layteam,layodds,advantage]]);
To (Enable the Google Sheets API advanced service):
var sheet_id = 'XXXXXXX';
var sheet = SpreadsheetApp.openById(sheet_id);
var sheet_page = sheet.getSheetByName('STACKTEST');
var avals = Sheets.Spreadsheets.Values.get(sheet_id, 'STACKTEST!A1:A').values;
var r = avals.length + 1;
var to_sheet = [
[triggerData.arguments[0],triggerData.arguments[1],triggerData.arguments[2],triggerData.arguments[3],triggerData.arguments[4]]
];
sheet_page.getRange(r, 1, to_sheet.length, to_sheet[0].length).setValues(to_sheet);
Test reduce time
Using the first method when 12800 rows filled (so add the values in row 12801):
Timeout Error (exceeded the 6 minute runtime limit)
Using Google Sheets API:
804ms
Using the first method when 1000 rows filled (so add the values in row 1001):
3493ms
Using Google Sheets API:
833ms
发布评论
评论(1)
python
您可以强制a超时。
有两种不同类型的超时类型:连接和读取。连接超时等待第一个连接。读取超时等待服务器发送的数据。将连接超时设置为大于一分钟的时间,但是读取超时时间不到几秒钟。
google-apps-scripts
很少有一个简单的脚本需要30秒的原因。可以通过取出所有不必要的
getValue()
调用并使用数组来优化您的代码。请参阅:可能是由于GetValue和cell Value和cell inserts造成的长时间处理时间这可以通过使用
.appendrow
而不是setValues()
,因为Appendrow操作是原子。由于该过程的异步性质,因此无法避免。但是,您始终可以根据ID重新排列数据。
同时执行限制为30
python
You can force a timeout.
There are two different types of timeout: Connect and read. Connect timeout waits for the first connection. Read timeout waits for the data to be sent by the server. Set the connect timeout to larger than a minute, but the read timeout to less than a few seconds.
google-apps-script
There's rarely reason for a simple script to take 30 seconds. Your code can be optimized a lot by taking out all unnecessary
getValue()
calls and using arrays. See: Long processing time likely due to getValue and cell insertsThis can be avoided by using
.appendRow
instead ofsetValues()
as appendRow operation is atomic.This cannot be avoided due to the async nature of the process. But, you can always rearrange the data later based on the id.
There's a simultaneous execution limit of 30