我试图实施Anton Soradoi在12/22/11提出的解决方案,以便使超过其最大执行时间的邮件合并脚本优雅地终止,等待一段时间,然后在其中找到它离开并继续这样做直到它的运行完成。 Here是引用帖子的链接。
脚本运行良好的时间(5分钟),然后抛出"执行失败:无效的参数:值(第80行)。另外,我不确定"其他" Anton Soradoi讨论过的脚本应该做的部分(再次运行我的menuItem1函数?)。我觉得我非常接近,任何帮助都会非常感激。我的代码如下:
//Creates the custom menu in the spreadsheet "Run Script"
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Script')
.addItem('Create Certs', 'menuItem1')
.addToUi();
}//Ends the custom menu in the spreadsheet
//Runs the menuItem 1 operation (Create Certs)
function menuItem1() {
//Defines the start row and calculates the number of rows to be processed
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = Browser.inputBox("Enter Start Row");
var endRow = Browser.inputBox("Enter End Row");
var numRows = (endRow - startRow) + 1; //this is the row height
var dataRange = sheet.getRange(startRow, 1, numRows, 7);
var counter =0;
var data = dataRange.getValues();
var templateDoc = DriveApp.getFileById("1baxSUxfSdzcVheR3Y2qgieWeSAqNybPfWct1913uRIc");
var templateCopy = templateDoc.makeCopy();
var templateCopyId = templateCopy.getId();
var dateOld;
var courseOld;
var fullNameOld;
var mailFrom = GmailApp.getAliases()
var team = "NWC Online PME Help Desk"
var startTime= (new Date()).getTime();
for (var i = 0; i < data.length; ++i) {
var doc = DocumentApp.openById(templateCopyId);
var body = doc.getActiveSection();
var row = data[i];
var date = row[0];
var nic = row[1];
var course = row[2];
var lastname = row[3];
var firstname = row[4];
var middle = row[5]
var email = row[6];
var subjectTxt = "NWC Online PME Course Certificate";
var fullBody = "PME COURSE COMPLETION CERTIFICATE" + "\n\n";
fullBody += "Your course completion certificate is attached." + "\n\n";
fullBody += "NOTES:" + "\n";
fullBody += "1. DO NOT telephone NWC to resolve PME certificate issues, email our Help Desk: pmecerthelp@usnwc.edu." + "\n";
fullBody += "2. NWC does NOT mail hardcopy certificates." + "\n";
fullBody += "3. NWC does not award certificates for the SNCO JPME courses." + "\n";
fullBody += "4. NWC course completion certificates are not automatically entered into your electronic training or service records." + "\n\n";
fullBody += "Regards," + "\n\n";
fullBody += "U.S. Naval War College Online PME Program Team"+ "\n\n";
fullBody += "Learn more about NWC's Online PME Program at the link below:" + "\n";
fullBody += "http://www.usnwc.edu/Academics/College-of-Distance-Education/PME-(1).aspx" + "\n";
var fullName = firstname+' '+middle+''+lastname
var fdate = Utilities.formatDate(new Date(date), "UTC", "d MMMM yyyy"); //converts UTC date
if(counter ==0){
body.replaceText('fullName',fullName);
body.replaceText('course', course);
body.replaceText('date', fdate);
}//Ends the if condition
else {
body.replaceText(fullNameOld,fullName);
body.replaceText(courseOld, course);
body.replaceText(dateOld, fdate);
}//Ends the else condition
dateOld = fdate;
courseOld = course;
fullNameOld = fullName;
counter ++
doc.saveAndClose();
var attachment = doc.getAs('application/pdf');
GmailApp.sendEmail(email, subjectTxt, fullBody, {name: team, attachments: attachment, from: mailFrom[1]});
var scriptProperties = PropertiesService.getScriptProperties();
var newStartRow= scriptProperties.getProperty('row');
for(var ii = newStartRow; ii <= data.length; ii++) {
var currTime = (new Date()).getTime();
if(currTime - startTime >= 300000) {
scriptProperties.setProperty("row", ii);
ScriptApp.newTrigger("menuItem1")
.timeBased()
.at(new Date(currTime+30000))
.create();
break;
}//Ends the if loop
}//Ends the second for loop
}//Ends the first for loop
}//Ends menuItem1
&#13;
答案 0 :(得分:0)
以下代码应该可以解决问题,不能按原样使用代码。请阅读以下内容:
//Creates the custom menu in the spreadsheet "Run Script"
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Script')
.addItem('Create Certs', 'menuItem1')
.addToUi();
}//Ends the custom menu in the spreadsheet
//Runs the menuItem 1 operation (Create Certs)
function menuItem1() {
//Defines the start row and calculates the number of rows to be processed
var sheet = SpreadsheetApp.getActiveSheet();
var scriptProperties = PropertiesService.getScriptProperties();
var startRow= scriptProperties.getProperty('StartRow');
var endRow = scriptProperties.getProperty('EndRow');
// Check to see if any property called startRow is present
if (startRow == null || endRow == null){ //If not present ask for the values from user
startRow = Number(Browser.inputBox("Enter Start Row"));
endRow = Number(Browser.inputBox("Enter End Row"));
scriptProperties.setProperty("EndRow", endRow)
} else { // if present ues those values for this run
startRow = Number(startRow) // Convert String to numbers
endRow = Number(endRow)
}
var numRows = (endRow - startRow) + 1; //this is the row height
var dataRange = sheet.getRange(startRow, 1, numRows, 7);
var counter =0;
var data = dataRange.getValues();
var templateDoc = DriveApp.getFileById("1baxSUxfSdzcVheR3Y2qgieWeSAqNybPfWct1913uRIc");
var templateCopy = templateDoc.makeCopy();
var templateCopyId = templateCopy.getId();
var dateOld;
var courseOld;
var fullNameOld;
var mailFrom = GmailApp.getAliases()
var team = "NWC Online PME Help Desk"
var startTime= (new Date()).getTime(); //set Start time
for (var i = 0; i < data.length; ++i) {
var doc = DocumentApp.openById(templateCopyId);
var body = doc.getActiveSection();
var row = data[i];
var date = row[0];
var nic = row[1];
var course = row[2];
var lastname = row[3];
var firstname = row[4];
var middle = row[5]
var email = row[6];
var subjectTxt = "NWC Online PME Course Certificate";
var fullBody = "PME COURSE COMPLETION CERTIFICATE" + "\n\n";
fullBody += "Your course completion certificate is attached." + "\n\n";
fullBody += "NOTES:" + "\n";
fullBody += "1. DO NOT telephone NWC to resolve PME certificate issues, email our Help Desk: pmecerthelp@usnwc.edu." + "\n";
fullBody += "2. NWC does NOT mail hardcopy certificates." + "\n";
fullBody += "3. NWC does not award certificates for the SNCO JPME courses." + "\n";
fullBody += "4. NWC course completion certificates are not automatically entered into your electronic training or service records." + "\n\n";
fullBody += "Regards," + "\n\n";
fullBody += "U.S. Naval War College Online PME Program Team"+ "\n\n";
fullBody += "Learn more about NWC's Online PME Program at the link below:" + "\n";
fullBody += "http://www.usnwc.edu/Academics/College-of-Distance-Education/PME-(1).aspx" + "\n";
var fullName = firstname+' '+middle+''+lastname
var fdate = Utilities.formatDate(new Date(date), "UTC", "d MMMM yyyy"); //converts UTC date
if(counter ==0){
body.replaceText('fullName',fullName);
body.replaceText('course', course);
body.replaceText('date', fdate);
}//Ends the if condition
else {
body.replaceText(fullNameOld,fullName);
body.replaceText(courseOld, course);
body.replaceText(dateOld, fdate);
}//Ends the else condition
dateOld = fdate;
courseOld = course;
fullNameOld = fullName;
counter ++
doc.saveAndClose();
var attachment = doc.getAs('application/pdf');
//GmailApp.sendEmail(email, subjectTxt, fullBody, {name: team, attachments: attachment, from: mailFrom[1]});
Utilities.sleep(30000)
var currTime = (new Date()).getTime();
if(currTime - startTime >= 240000) { //Check if the script run is over 4minutes , at 5 min the excution might as well might have been terminated
scriptProperties.setProperty("StartRow", startRow + i+1); //The new start, just number of iteration done plus 1 to start from row after that
ScriptApp.newTrigger("menuItem1")
.timeBased()
.at(new Date(currTime+30000)) //restart in 30 secs!
.create();
Logger.log("Last email sent to: " + email)
Logger.log("Next Run start at row: " + startRow + i+1)
return; // End current run.
}//Ends the if Block
}//Ends the first for loop
}//Ends menu
这种方法的工作方式是使用scriptProperties存储已处理的lastRow和endRow。如果找不到这些值,它会要求用户输入!
var scriptProperties = PropertiesService.getScriptProperties();
var startRow= scriptProperties.getProperty('StartRow');
var endRow = scriptProperties.getProperty('EndRow');
// Check to see if any property called startRow is present
if (startRow == null || endRow == null){ //If not present ask for the values from user
startRow = Browser.inputBox("Enter Start Row");
endRow = Browser.inputBox("Enter End Row");
scriptProperties.setProperty("EndRow", endRow)
} else { // if present ues those values for this run
startRow = Number(startRow) // Convert String to numbers
endRow = Number(endRow)
}
下面的代码将检查它是否已超过4分钟标记(如果是),设置时间触发器并将startrow属性修改为最后一个处理后的新行。然后使用return退出该函数。
var currTime = (new Date()).getTime();
if(currTime - startTime >= 240000) { //Check if the script run is over 4minutes , at 5 min the excution might as well might have been terminated
scriptProperties.setProperty("StartRow", startRow + i+1); //The new start, just number of iteration done plus 1 to start from row after that
ScriptApp.newTrigger("menuItem1")
.timeBased()
.at(new Date(currTime+30000)) //restart in 30 secs!
.create();
Logger.log("Last email sent to: " + email)
Logger.log("Next Run start at row: " + startRow + i+1)
return; // End current run.
}//Ends the if Block
<强>调试:强> 您会注意到GmailApp行附近的这些行:
//GmailApp.sendEmail(email, subjectTxt, fullBody, {name: team, attachments: attachment, from: mailFrom[1]});
Utilities.sleep(30000)
注释掉你的GamilApp系列,而不是睡了30秒,这将有助于测试代码。运行代码后,在&#34; View&#34;下找到执行记录。并找到这些值:
Logger.log("Last email sent to: " + email)
Logger.log("Next Run start at row: " + startRow + i+1)
通过这种方式,您可以手动匹配最后发送的电子邮件和下一个startRow,以确保在您上线之前一切正常。
修改强>
最后,要在遇到任何问题时重置脚本属性,请运行以下函数。
function resetScript(){
var scriptProperties = PropertiesService.getScriptProperties();
Logger.log(scriptProperties.getProperties())
scriptProperties.deleteAllProperties()
}
希望有所帮助
答案 1 :(得分:0)
在一天的大部分时间里与Jack Brown一起工作,这是最终答案:
//Creates the custom menu in the spreadsheet "Run Script"
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Script')
.addItem('Create Certs', 'menuItem1')
.addToUi();
}//Ends the custom menu in the spreadsheet
//Runs the menuItem 1 operation (Create Certs)
function menuItem1() { //Defines the start row and calculates the number of rows to be processed
var sheet = SpreadsheetApp.getActiveSheet();
var scriptProperties = PropertiesService.getScriptProperties(); // starts the Script Properties service for storing the last row completed
var startRow= scriptProperties.getProperty('StartRow');
var endRow = scriptProperties.getProperty('EndRow');
// Check to see if any property called startRow is present
if (startRow == null || endRow == null){ //If not present ask for the startRow and endRow values from user
startRow = Number(Browser.inputBox("Enter Start Row"));
endRow = Number(Browser.inputBox("Enter End Row"));
scriptProperties.setProperty("EndRow", endRow)
}// ends the if condition
else { // if present ues those values for this run
startRow = Number(startRow) // Convert startRow string to a number
endRow = Number(endRow) // Convert endRow string to a number
} //end the else condition
var numRows = (endRow - startRow) + 1; //this is the row height
if(numRows < 1){
scriptProperties.deleteAllProperties()
return;
} //ends the if condition
var dataRange = sheet.getRange(startRow, 1, numRows, 7);
var counter =0;
var data = dataRange.getValues();
var templateDoc = DriveApp.getFileById("1baxSUxfSdzcVheR3Y2qgieWeSAqNybPfWct1913uRIc");
var templateCopy = templateDoc.makeCopy();
var templateCopyId = templateCopy.getId();
var dateOld;
var courseOld;
var fullNameOld;
var mailFrom = GmailApp.getAliases() //gets the alias address the email is sent from
var team = "NWC Online PME Help Desk"
var startTime= (new Date()).getTime(); //sets the script Start time
for (var i = 0; i < data.length; ++i) { // Populates the certificate with row data and builds the custom email
var doc = DocumentApp.openById(templateCopyId);
var body = doc.getActiveSection();
var row = data[i]; // specifies the active row [i]
var date = row[0]; // date on the cert for row [i] (column 0)
var nic = row[1]; // course nickname for row [i] (column 1)
var course = row[2]; // course name for row [i] (column 2)
var lastname = row[3]; // learner's last name for row [i] (column 3)
var firstname = row[4]; // learner's first name for row [i] (column 4)
var middle = row[5]; // learner's middle initial for row [i] (column 5)
var email = row[6]; // learner's email address for row [i] (column 6)
var subjectTxt = "NWC Online PME Course Certificate"; // email's subject line
var fullBody = "PME COURSE COMPLETION CERTIFICATE" + "\n\n"; //email's header
fullBody += "Your course completion certificate is attached." + "\n\n";
fullBody += "NOTES:" + "\n";
fullBody += "1. DO NOT telephone NWC to resolve PME certificate issues, email our Help Desk: pmecerthelp@usnwc.edu." + "\n";
fullBody += "2. NWC does NOT mail hardcopy certificates." + "\n";
fullBody += "3. NWC does not award certificates for the SNCO JPME courses." + "\n";
fullBody += "4. NWC course completion certificates are not automatically entered into your electronic training or service records." + "\n\n";
fullBody += "Regards," + "\n\n";
fullBody += "U.S. Naval War College Online PME Program Team"+ "\n\n";
fullBody += "Learn more about NWC's Online PME Program at the link below:" + "\n";
fullBody += "http://www.usnwc.edu/Academics/College-of-Distance-Education/PME-(1).aspx" + "\n";
var fullName = firstname+' '+middle+''+lastname
var fdate = Utilities.formatDate(new Date(date), "UTC", "d MMMM yyyy"); //converts the UTC date to the desired format
if(counter == 0){
body.replaceText('fullName',fullName);
body.replaceText('course', course);
body.replaceText('date', fdate);
}//Ends the if condition
else {
body.replaceText(fullNameOld,fullName);
body.replaceText(courseOld, course);
body.replaceText(dateOld, fdate);
}//Ends the else condition
dateOld = fdate;
courseOld = course;
fullNameOld = fullName;
counter ++
doc.saveAndClose(); //creates the learner's certificate
var attachment = doc.getAs('application/pdf'); // converts the learner's certificate from a doc file to a PDF
GmailApp.sendEmail(email, subjectTxt, fullBody, {name: team, attachments: attachment, from: mailFrom[1]}); // sends the learner's certificate as an attachment to the email
// Utilities.sleep(2500) // When sleeping the GmailApp line, enables testing of the script without impact on Gmail's email quota
sheet.getRange(startRow + i , 8).setValue("Done at: "+ new Date()) // puts the sent date/time in column 8 of the spreadsheet
var currTime = (new Date()).getTime(); //gets the current date/time for the script to determine run time
if(currTime - startTime >= 240000) { //Checks if the script run is over 4 minutes
clearTriggers() //clears the script's triggers
scriptProperties.setProperty("StartRow", startRow + i+1); // The new startRow, just number of iterations done + 1 to start with the next row
ScriptApp.newTrigger("menuItem1")
.timeBased()
.at(new Date(currTime+60000)) //restarts the script in 60 sec to finish cleanly
.create();
Logger.log("Last email sent to: " + email)
Logger.log("Next Run start at row: " + (startRow + i+1))
return; // Ends the current run.
}//Ends the if condition
}//Ends the first for loop
// Logger.log("This shouldnt run") was used in testing, not needed now.
DriveApp.getFileById(templateCopyId).setTrashed(true); // deletes the working copy of the document template
clearTriggers() // function defined in Reset Script
resetScript() // function defined in Reset Script
}//Ends menuItem1
//Comments
//Jagannathan
//Ok this seems to work, also note i modified this:
//.at(new Date(currTime+60000))
//To run after minute, the trigger are not sensititve to 30 sec, so they where not triggering properply.
//Again copy this as is run it your spreadsheet when you get a chance.
//Once you are satisfied with the mock run, remove the comment form Gmail and comment sleep and run it
//Leave the sheet.getRange() line to so that you keep on eye on how it triggers. And in case it fails you know where to start from.
这是定义resetScript()和clearTriggers()
的附加脚本文件
function resetScript(){
var scriptProperties = PropertiesService.getScriptProperties();
Logger.log(scriptProperties.getProperties())
scriptProperties.deleteAllProperties()
}
function clearTriggers(){
var triggers = ScriptApp.getUserTriggers(SpreadsheetApp.getActive())
for (var i =0 ; i< triggers.length ; i++)
{
if(triggers[i].getHandlerFunction() == "menuItem1") {
ScriptApp.deleteTrigger(triggers[i])
}
}
}