Сценарий Google Apps Превышено максимальное время выполнения - PullRequest
0 голосов
/ 03 апреля 2020

Я создаю свой собственный код сценария приложения для обновления даты из файла дампа. Большую часть времени я сталкиваюсь с проблемой «Превышено максимальное время выполнения». Но код работал нормально. он импортирует и обновляет статус для данных (16,5 тыс. строк) из таблицы (29 тыс. строк). Можете ли вы помочь ускорить работу кода?

function update_main_master() {
  var xngSs = SpreadsheetApp.openById('XXXX');
  var xngSh = xngSs.getSheetByName('XNG Clean Data');
  var MasterSs = SpreadsheetApp.openById('YYY');
  var MasterSh = MasterSs.getSheetByName('Master Sheet');
  var MasterData = MasterSh.getDataRange().getValues();
  var xngData = xngSh.getDataRange().getValues();

  //  clearFilter()
  if (MasterSh.getFilter() != null) {
    MasterSh.getFilter().remove();
  }

  xngData.splice(0, 1);
  MasterData.splice(0, 1);
  var OrderNumberMasterSh = [];
  var PathNameMasterSh = [];
  for (var i = 0; i < MasterData.length; i++) {
    OrderNumberMasterSh.push(MasterData[i][1]);
    PathNameMasterSh.push(MasterData[i][2]);
  }
  var i = 0;
  for (var x = 0; x < xngData.length && xngData[x][3] != undefined; x++) {
    var OrderNumber = xngData[x][3];
    var OrderDate = xngData[x][2];
    var PathName = xngData[x][4];
    var CustomerName = xngData[x][5];
    var MW_contractor = xngData[x][8];
    var OrderStatus = xngData[x][9];
    var OrderStage = xngData[x][10];
    var ProjectID = xngData[x][14];
    var OrderType = xngData[x][41];
    var StageDate = xngData[x][11];
    var InService = xngData[x][28];
    var RejectedReason = xngData[x][31];
    var District = xngData[x][15];
    var LinkID = xngData[x][24];
    var NewOrder = 'New Order';

    if (MW_contractor == 'A' || MW_contractor == 'B' || MW_contractor == 'C') {
      if (
        OrderType == 'New' ||
        OrderType == 'Repeater' ||
        OrderType == 'Visibility'
      ) {
        //        if(OrderType == "New" || OrderType == 'Repeater')

        var index = OrderNumberMasterSh.indexOf(OrderNumber);

        if (index == -1) {
          MasterData.push([
            OrderDate,
            OrderNumber,
            PathName,
            CustomerName,
            ProjectID,
            MW_contractor,
            OrderStatus,
            OrderStatus,
            OrderStage,
            OrderType,
            StageDate,
            InService,
            '',
            District,
            '',
            NewOrder,
            '',
            '',
            '',
            '',
            '',
            '',
            '',
            '',
            '',
            '',
            '',
            '',
            '',
            '',
            '',
            '',
            '',
            '',
            '',
            '',
            '',
            '',
            '',
            '',
            '',
            '',
            '',
            '',
            '',
            '',
            '',
            '',
            RejectedReason,
            '',
            '',
            '',
            '',
            '',
            '',
            '',
            '',
            '',
            '',
          ]);
        } else {
          MasterData[index][4] = ProjectID;
          MasterData[index][5] = MW_contractor;
          MasterData[index][7] = OrderStatus;
          MasterData[index][8] = OrderStage;
          MasterData[index][10] = StageDate;
          MasterData[index][11] = InService;

          if (MasterData[index][51] == '') {
            MasterData[index][51] = LinkID;
          }

          if (
            OrderStatus == 'IN-PROCESS' ||
            OrderStatus == 'CANCELLED' ||
            OrderStatus == 'REJECTED'
          ) {
            MasterData[index][6] = OrderStatus;
          }

          if (OrderStatus == 'COMPLETED') {
            MasterData[index][6] = 'LIVE';
          }
          if (OrderStatus == 'REJECTED' && MasterData[index][48] == '') {
            MasterData[index][48] = RejectedReason;
          }
        }
      }
    }
  }

  var ContorlSS = SpreadsheetApp.openById('ZZZZ');
  var ContorlSh = ContorlSS.getSheetByName('Setup');
  ContorlSh.getRange('F6').setValue('Updated');
  ContorlSh.getRange('G6').setValue(new Date());

  MasterSh.getRange(2, 1, MasterData.length, MasterData[0].length).setValues(
    MasterData
  );
  SpreadsheetApp.flush();
}

Я создаю собственный код сценария приложения для обновления дата из файла дампа. Большую часть времени я сталкиваюсь с проблемой «Превышено максимальное время выполнения». Но код работал нормально. он импортирует и обновляет статус для данных (16,5 тыс. строк) из листа (29 тыс. строк). Можете ли вы помочь ускорить работу кода?

1 Ответ

0 голосов
/ 06 апреля 2020

Вы достигли лимита времени выполнения, который для большинства аккаунтов составляет 6 минут. Чтобы избежать этого, вы можете разделить ваш l oop на разные исполнения, установив временной триггер, который будет запускать каждое последующее выполнение после завершения предыдущего. Вам нужно будет сделать следующее:

  • Проверить время выполнения после каждой итерации. Если это время близко к сроку, остановите выполнение. Для этого вы можете использовать объект Date .

  • Создать следующий основанный на времени триггер в конце вашей функции: after (durationMilliseconds) . Благодаря этому вы можете запускать любую функцию, указанную вами, по истечении указанного вами количества миллисекунд. После каждого выполнения будет создан триггер для запуска следующего.

  • Поскольку вы хотите разделить l oop, вы должны сохранить счетчик l oop (x) где-то (вы могли бы использовать PropertiesService в конце каждого выполнения или записать его в электронную таблицу) и извлечь его в начале следующего, чтобы каждый сценарий при последовательном выполнении знал, где возобновить l oop. См., Например, этот ответ , если вы не знаете, как сохранять и извлекать свойства скрипта.

  • Прямо сейчас вы храните все нужные данные. в двумерном массиве MasterData и записи этих данных в электронную таблицу с setValues в конце кода. Поскольку это действие происходит только после того, как ваш l oop завершен, это не будет целесообразно, если вы разделите l oop на несколько исполнений. Я бы посоветовал вам изменить ваш код так, чтобы процесс записи выполнялся внутри l oop, и убрать setValues из конца вашего кода. Вы должны будете изменить свой код, как в следующих примерах.

Например, попробуйте изменить это:

MasterData[index][48] = RejectedReason;

С этим:

MasterSh.getRange(index + 1, 49).setValue(RejectedReason);

И это:

MasterData.push([OrderDate, OrderNumber, ...]);

С этим:

MasterSh.appendRow([OrderDate, OrderNumber, ...]);

Пример кода (проверьте встроенные комментарии):

function update_main_master() {
  var begin = new Date(); // Time when execution begins
  // Your code before loop
  var x_old = // Retrieve x stored in previous execution (from PropertiesService? Spreadsheet?) (should be 0 if first execution)
  var timeLimit = 1000 * 60 * 5; // 5 minutes (in milliseconds)
  while (new Date() - begin < timeLimit) { // Check if 5 minutes passed since execution start
    for (var x = 0; x < xngData.length && xngData[x][3] != undefined; x++) {
      // Your code inside loop
    }
  }
  // Store current x index (using PropertiesService? Or write to the spreadsheet itself?
  var ContorlSS = SpreadsheetApp.openById('ZZZZ');
  var ContorlSh = ContorlSS.getSheetByName('Setup');
  ContorlSh.getRange('F6').setValue('Updated');
  ContorlSh.getRange('G6').setValue(new Date());
  if (x < xngData.length) { // Create trigger if x hasn't reach the total number of iteration
    ScriptApp.newTrigger("update_main_master")
    .timeBased()
    .after(1000 * 60) // This fires the function 1 minute after the current execution ends. Change this time according to your preferences
    .create();  
  }
}

Ссылка:

...