在达到时间限制时提取脚本结束的位置

时间:2017-04-07 13:48:26

标签: performance google-apps-script google-sheets

我试图实施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;
&#13;
&#13;

2 个答案:

答案 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]) 
   }
 }
 
}