Превышено максимальное время выполнения - PullRequest
1 голос
/ 12 ноября 2019

Вот мой код do:

  1. Реплицирует электронную таблицу и выдает ее в папку gdrive (количество репликаций зависит от количества сотрудников в моем файле конфигурации). На данный момент у меня более 800 сотрудников.
  2. После репликации каждая электронная таблица в папке gdrive публикуется в формате html. (здесь я использовал цикл)
  3. Получите ссылку pubHTML для каждой электронной таблицы и поместите ее в мой файл конфигурации.

Я получаю превышенное максимальное время выполнения, когда я нахожусь на шаге 3, который заключается в том, чтобы получить pubHTML и поместить его в мой файл конфигурации.

Мой кодработает как положено. Я хочу избежать максимального предела ошибок выполнения.

  function replicateCards() {
  var ss = SpreadsheetApp.openById('configfile--xxxx');
  var copyCard = SpreadsheetApp.openById('replicateCard-xxxx');
  var getID = DriveApp.getFileById(copyCard.getId())
  var card = copyCard.getSheetByName("Card");
  var mastersheet = ss.getSheetByName("Mastersheet");
  var getLastRow = mastersheet.getLastRow();
  var destinationFolder = DriveApp.getFolderById('gdrivefolder-xxxx');
  var changeColorToGrayList = card.getRangeList(['C7', 'E7', 'G7', 'I7', 'K7', 'M7', 'O7', 'Q7',
                                                 'C9', 'E9', 'G9', 'I9', 'K9', 'M9', 'O9', 'Q9',
                                                 'C11', 'E11', 'G11', 'I11', 'K11', 'M11', 'O11', 'Q11']);
  var setValueToZero = card.getRangeList(['C8', 'E8', 'G8', 'I8', 'K8', 'M8', 'O8', 'Q8',
                                          'C10', 'E10', 'G10', 'I10', 'K10', 'M10', 'O10', 'Q10',
                                          'C12', 'E12', 'G12', 'I12', 'K12', 'M12', 'O12', 'Q12']);
  for (i = 1; i < getLastRow; i++) {
    var badgeStatus = mastersheet.getRange(i + 1, 5).getValue();
    if (badgeStatus == "") {
      var employeeNumber = mastersheet.getRange(i + 1, 1).getValue();
      var employeeName = mastersheet.getRange(i + 1, 2).getValue();
      copyCard.getRange("H3").setValue(employeeNumber);
      copyCard.getRange("C3").setValue(employeeName);
      SpreadsheetApp.flush();
      if(mastersheet.getRange(1 + i, 5).getValue() != "completed"){
        getID.makeCopy(employeeNumber, destinationFolder);
        mastersheet.getRange(1 + i, 5).setValue("completed");
      }
      //          Logger.log(i);
      SpreadsheetApp.flush();

    }
  }
  var files = DriveApp.getFolderById(SpreadsheetApp.openById("configFile-xxxx").getSheetByName("Config Sheet").getRange("B1").getValue()).getFiles();
  //var fileIter = 1;
  var employeeNumbers = mastersheet.getRange("A2:A").getValues();
  var employeeNumbersTrunc = []
  for(var i = 0; i < employeeNumbers.length; i++){
    if(employeeNumbers[i][0] != "")
      employeeNumbersTrunc.push("" + employeeNumbers[i][0]);
  }
  Logger.log(employeeNumbersTrunc);

  while (files.hasNext()) {
    var file = files.next();
    /*var Found = false;
    for (var j = 0; j < ; fileIter++) {
      if (employeeNumber2[j][0] == file.getName()) {
        Found = true;
      }
    }//*/
    if (employeeNumbersTrunc.indexOf(file.getName())==-1) {
      continue;
    }else if(mastersheet.getRange(2 + (employeeNumbersTrunc.indexOf(file.getName())), 9).getValue() != ""){
      continue;
    }
    try {
      var fileId = file.getId();
      var fileName = file.getName();
      var revisions = Drive.Revisions.list(fileId);
      var lastRevisionId = revisions.items[revisions.items.length - 1].id;
      // get the resource and set the publish parameters
      var resource = Drive.Revisions.get(fileId, lastRevisionId);
      //       Logger.log(resource);
      resource.published = true;
      resource.publishAuto = true;
      resource.publishedOutsideDomain = true;
      // publish to the web
      Drive.Revisions.update(resource, fileId, lastRevisionId);
      SpreadsheetApp.flush();
      var openByID = SpreadsheetApp.openById(fileId);
      SpreadsheetApp.flush();
      var googleDriveSheet = openByID.getUrl().replace("edit", "pubhtml"); // or replace("edit", "pub");
      SpreadsheetApp.flush();
      Logger.log(file.getName());
      Logger.log(employeeNumbersTrunc.indexOf(file.getName()));
      mastersheet.getRange(2 + (employeeNumbersTrunc.indexOf(file.getName())), 9).setValue(googleDriveSheet);
      SpreadsheetApp.flush();
    } catch (err) {
      Logger.log(err);
    }
  }
}

Запускать код только один раз без превышения максимальной ошибки времени выполнения. Есть предложения?

1 Ответ

0 голосов
/ 13 ноября 2019

Код ниже изменен по сравнению с тем, что я использовал ранее. Подобный подход позволяет полностью выполнить пакет, который сам по себе не может быть выполнен в течение срока выполнения . Зная, сколько времени занимает одна операция в пакете, вы можете сохранить свой прогресс в Свойствах до достижения этого предела и программно создать триггер для возобновления обработки.

Вам нужно будет сделать несколько вещей, чтобы он заработал:

  1. Вам нужно изменить мою функцию getEmployees_(), чтобы точно получить сотрудников из вашего конфигурационного файла.
  2. Как яКак уже упоминалось в моем комментарии, вам необходимо провести рефакторинг своего кода, чтобы выполнить репликацию для одного сотрудника. Этот код должен идти в моей функции replicateForEmployee_().
  3. Запустить функцию determineTimes(), чтобы узнать, сколько времени занимает получение сотрудников и репликация файлов.
  4. Вставьте результаты determineTimes() в *Функция 1022 *.

Вывод determineTimes() будет отображаться на странице Выполнения (Вид> Выполнения). Разверните строку выполнения, и вы увидите продолжительность, как показано на рисунке.

Execution logs

/**
 * Get all of the employees in the sheet. Assumes row in the sheet is one employee. Adjust the range as needed.
 * @returns {Object[][]}
 */
function getEmployees_() {
  var source = SpreadsheetApp.openById("configfile--xxxx");
  var sheet = source.getSheetByName("Mastersheet");
  return sheet.getRange(1, 1, sheet.getLastRow(), sheet.getLastColumn()).getValues();
}

/**
 * Refactor your current code so that this function will replicate all necessary files for a single
 * employee. The function will be called for every single employee.
 * @param {Object[]} employee - The row representing the employee in your config file
 */
function replicateForEmployee_(employee) {
  // Execute your replication process for a SINGLE employee here
}

/**
 * Run this, and then examine your script executions (View > Executions) to see how long each
 * function takes. The resulting durations should replace the corresponding values in the replicate()
 * function (I would recommend rounding up, so 458 --> 500ms).
 */
function determineTimes() {
  console.time("timeToGetEmployees");
  var employees = getEmployees_(); // Get all of the employees
  console.timeEnd("timeToGetEmployees");

  console.time("replicationDuration");
  replicateForEmployee_(employees[0]); // Execute replication once
  console.timeEnd("replicationDuration");
}

/**
 * Replicates the files. When approaching the time limit, will save location and set a trigger to
 * continue from stopping point. Emails user upon completion.
 * @param {Boolean} isFromTrigger
 * @returns {undefined}
 */
function replicate(isFromTrigger) {
  var employees = getEmployees(); // Get all of the employees
  var timeToGetEmployees = 1000; // Assume 1 second to execute getEmployees()
  var replicationDuration = 500; // Number of milliseconds it takes to execute replication for one employee.
  var maxExecutionTime = 360000 - timeToGetEmployees; // 6 mins - time already used to get employees

  var continueFrom = 0; // If first execution, will be zero. Otherwise, get the index to start from.
  if (isFromTrigger === true) {
    continueFrom = parseInt(PropertiesService.getScriptProperties().getProperty("continueFrom"), 10);
  }
  var lapsedTime = 0; // ESTIMATED amount of time that has lapsed since the replication started

  for (var i = continueFrom; i < employees.length; i++) {
    // Replicate files for the employee
    replicateForEmployee_(employees[i]);

    // Checks how much time you have left
    lapsedTime += replicationDuration;
    if (lapsedTime >= (maxExecutionTime - replicationDuration)) { // warn just before timing out
      PropertiesService.getScriptProperties().setProperty("continueFrom", i + 1); // save the last iterator value + 1
      createAfterTrigger("replicateFromTrigger", 60000); // Start again in one minute
      console.info("About to time out. Last iterator: " + i);
      return;
    }
  }

  deleteAllTriggers(); // Cleanup any lingering triggers
  PropertiesService.getScriptProperties().deleteProperty("continueFrom"); // Clean up properties

  // Send completion email
  MailApp.sendEmail(Session.getEffectiveUser().getEmail(), "Replication Complete", "");
}

/**
 * Should ONLY ever be called from a clock trigger.
 * @returns {undefined}
 */
function replicateFromTrigger() {
  replicate(true);
}

/**
 * Create a new trigger to execute the specified function after a certain amount of time.
 * @param {String} functionName - The name of the function to execute
 * @param {Number} milliseconds - The duration (in milliseconds) after the current time when the trigger should run
 * @returns {undefined}
 */
function createAfterTrigger(functionName, milliseconds) {
  ScriptApp.newTrigger(functionName)
  .timeBased()
  .after(milliseconds)
  .create();
}

/**
 * Deletes all triggers in the current project.
 * @returns {undefined}
 */
function deleteAllTriggers() {
  var triggers = ScriptApp.getProjectTriggers();
  for (var i = 0; i < triggers.length; i++) {
    ScriptApp.deleteTrigger(triggers[i]);
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...