解析对象数组时保存 Google 应用脚本状态,稍后从中断处继续
Save Google App Script state while parsing an object array and continue where left off later on
我正在使用这个简单的 google 应用程序脚本来解析所有可用的 Google 站点并转储各个页面的 html 内容。有很多页所以脚本最终会 运行 进入 6 分钟的时间限制。
是否有可能以某种方式使用 PropertiesService 来保存当前进度(尤其是在数组循环中)并在稍后停止的地方继续?
var sites = SitesApp.getAllSites("somedomain.com");
var exportFolder = DriveApp.getFolderById("a4342asd1242424folderid-");
// Cycle through all sites
for (var i in sites){
var SiteName = sites[i].getName();
var pages = sites[i].getAllDescendants();
// Create folder in Drive for each site name
var siteFolder = exportFolder.createFolder(SiteName)
for (var p in pages){
// Get page name and url
var PageUrl = pages[p].getUrl();
//Dump the raw html content in the text file
var htmlDump = pages[p].getHtmlContent();
siteFolder.createFile(PageUrl+".html", htmlDump)
}
}
我可以想象如何使用属性服务将当前行号存储在电子表格中,并从中断的地方继续。但是,如何使用包含 Sites 或 Pages?
等对象的数组来完成此操作?
如果您能够在 6 分钟内处理 1 个网站的所有页面,那么您可以尝试先将网站名称保存在 sheet 或 props 中,具体取决于数量。并继续处理每个 运行 的 n 个站点。也可以尝试 SitesApp.getAllSites(domain, start, max) 并在递增后将起始值保存在 props 中。
如果您不能在 6 分钟内处理它们,可以对页面执行类似的操作。
SitesApp.getAllDescendants(options)
将对象与属性服务一起使用
根据 quotas the maximum size of something you can store in the properties service is 9kb. With a total of 500kb. So if your object is less than this size, it should be no problem. That said, you will need to convert the object to a string with JSON.stringify()
and when you retrieve it, use JSON.parse
.
在 运行 时间限制附近工作
解决限制的常用方法是围绕属性服务和触发器构建一个进程。本质上你让脚本跟踪时间,如果它开始需要很长时间,你让它保存它的位置然后创建一个触发器以便脚本 运行s 在 10 秒(或多长时间)后再次出现你想要的),例如:
function mainJob(x) {
let timeStart = new Date()
console.log("Starting at ", timeStart)
for (let i = x; i < 500000000; i++){ // NOTE THE i = x
// MAIN JOB INSTRUCTIONS
let j = i
// ...
// Check Time
let timeCheck = new Date()
if (timeCheck.getTime() - timeStart.getTime() > 30000) {
console.log("Time limit reached, i = ", i)
// Store iteration number
PropertiesService
.getScriptProperties()
.setProperty('PROGRESS', i)
console.log("stored value of i")
// Create trigger to run in 10 seconds.
ScriptApp.newTrigger("jobContinue")
.timeBased()
.after(10000)
.create()
console.log("Trigger created for 10 seconds from now")
return 0
}
}
// Reset progress counter
PropertiesService
.getScriptProperties()
.setProperty('PROGRESS', 0)
console.log("job complete")
}
function jobContinue() {
console.log("Restarting job")
previousTrigger = ScriptApp.getProjectTriggers()[0]
ScriptApp.deleteTrigger(previousTrigger)
console.log("Previous trigger deleted")
triggersRemain = ScriptApp.getProjectTriggers()
console.log("project triggers", triggersRemain)
let progress = PropertiesService
.getScriptProperties()
.getProperty('PROGRESS')
console.log("about to start main job again at i = ", progress)
mainJob(progress)
}
function startJob() {
mainJob(0)
}
说明
- 这个脚本只有一个 for 循环,有 5 亿次迭代,其中它将
i
分配给 j
,这只是一个可能超过 运行 的长作业的示例] 限时.
- 脚本通过调用函数
startJob
启动,该函数调用 mainJob(0)
.
- 在
mainJob
之内
- 它首先创建一个
Date
对象来获取 mainJob
的开始时间。
- 它采用参数
0
并使用它来将 for
循环初始化为 0
,就像通常初始化 for
循环一样。
- 在每次迭代结束时,它都会创建一个新的
Date
对象来与 mainJob
开始时创建的对象进行比较。在示例中,它设置为查看脚本是否已 运行ning 30 秒,这显然可以延长但保持在限制以下。
- 如果超过 30 秒,它会将
i
的值存储在属性服务中,然后在 10 秒内创建到 运行 jobContinue
的触发器。
- 10 秒后,函数
jobContinue
为 i
的值调用属性服务,并使用从属性服务返回的值调用 mainJob
。
jobContinue
还会删除刚刚创建的触发器以保持干净。
- 这个脚本在新项目中应该运行原样,试试吧!当我 运行 它时,它需要大约 80 秒,所以它第一次 运行s,创建一个触发器,再次 运行s,创建一个触发器,再次 运行s然后最终完成 for 循环。
参考资料
我正在使用这个简单的 google 应用程序脚本来解析所有可用的 Google 站点并转储各个页面的 html 内容。有很多页所以脚本最终会 运行 进入 6 分钟的时间限制。
是否有可能以某种方式使用 PropertiesService 来保存当前进度(尤其是在数组循环中)并在稍后停止的地方继续?
var sites = SitesApp.getAllSites("somedomain.com");
var exportFolder = DriveApp.getFolderById("a4342asd1242424folderid-");
// Cycle through all sites
for (var i in sites){
var SiteName = sites[i].getName();
var pages = sites[i].getAllDescendants();
// Create folder in Drive for each site name
var siteFolder = exportFolder.createFolder(SiteName)
for (var p in pages){
// Get page name and url
var PageUrl = pages[p].getUrl();
//Dump the raw html content in the text file
var htmlDump = pages[p].getHtmlContent();
siteFolder.createFile(PageUrl+".html", htmlDump)
}
}
我可以想象如何使用属性服务将当前行号存储在电子表格中,并从中断的地方继续。但是,如何使用包含 Sites 或 Pages?
等对象的数组来完成此操作?如果您能够在 6 分钟内处理 1 个网站的所有页面,那么您可以尝试先将网站名称保存在 sheet 或 props 中,具体取决于数量。并继续处理每个 运行 的 n 个站点。也可以尝试 SitesApp.getAllSites(domain, start, max) 并在递增后将起始值保存在 props 中。
如果您不能在 6 分钟内处理它们,可以对页面执行类似的操作。 SitesApp.getAllDescendants(options)
将对象与属性服务一起使用
根据 quotas the maximum size of something you can store in the properties service is 9kb. With a total of 500kb. So if your object is less than this size, it should be no problem. That said, you will need to convert the object to a string with JSON.stringify()
and when you retrieve it, use JSON.parse
.
在 运行 时间限制附近工作
解决限制的常用方法是围绕属性服务和触发器构建一个进程。本质上你让脚本跟踪时间,如果它开始需要很长时间,你让它保存它的位置然后创建一个触发器以便脚本 运行s 在 10 秒(或多长时间)后再次出现你想要的),例如:
function mainJob(x) {
let timeStart = new Date()
console.log("Starting at ", timeStart)
for (let i = x; i < 500000000; i++){ // NOTE THE i = x
// MAIN JOB INSTRUCTIONS
let j = i
// ...
// Check Time
let timeCheck = new Date()
if (timeCheck.getTime() - timeStart.getTime() > 30000) {
console.log("Time limit reached, i = ", i)
// Store iteration number
PropertiesService
.getScriptProperties()
.setProperty('PROGRESS', i)
console.log("stored value of i")
// Create trigger to run in 10 seconds.
ScriptApp.newTrigger("jobContinue")
.timeBased()
.after(10000)
.create()
console.log("Trigger created for 10 seconds from now")
return 0
}
}
// Reset progress counter
PropertiesService
.getScriptProperties()
.setProperty('PROGRESS', 0)
console.log("job complete")
}
function jobContinue() {
console.log("Restarting job")
previousTrigger = ScriptApp.getProjectTriggers()[0]
ScriptApp.deleteTrigger(previousTrigger)
console.log("Previous trigger deleted")
triggersRemain = ScriptApp.getProjectTriggers()
console.log("project triggers", triggersRemain)
let progress = PropertiesService
.getScriptProperties()
.getProperty('PROGRESS')
console.log("about to start main job again at i = ", progress)
mainJob(progress)
}
function startJob() {
mainJob(0)
}
说明
- 这个脚本只有一个 for 循环,有 5 亿次迭代,其中它将
i
分配给j
,这只是一个可能超过 运行 的长作业的示例] 限时. - 脚本通过调用函数
startJob
启动,该函数调用mainJob(0)
. - 在
mainJob
之内- 它首先创建一个
Date
对象来获取mainJob
的开始时间。 - 它采用参数
0
并使用它来将for
循环初始化为0
,就像通常初始化for
循环一样。 - 在每次迭代结束时,它都会创建一个新的
Date
对象来与mainJob
开始时创建的对象进行比较。在示例中,它设置为查看脚本是否已 运行ning 30 秒,这显然可以延长但保持在限制以下。 - 如果超过 30 秒,它会将
i
的值存储在属性服务中,然后在 10 秒内创建到 运行jobContinue
的触发器。
- 它首先创建一个
- 10 秒后,函数
jobContinue
为i
的值调用属性服务,并使用从属性服务返回的值调用mainJob
。 jobContinue
还会删除刚刚创建的触发器以保持干净。- 这个脚本在新项目中应该运行原样,试试吧!当我 运行 它时,它需要大约 80 秒,所以它第一次 运行s,创建一个触发器,再次 运行s,创建一个触发器,再次 运行s然后最终完成 for 循环。