Выборка XML в Google App Script заканчивается после превышения максимального времени выполнения - PullRequest
0 голосов
/ 18 марта 2020

Я пытаюсь получить XML с помощью Google App Script и затем передать эти значения в Google Sheets. Все отлично работает за несколько итераций. Если я попытаюсь сделать больше, я превышу максимальное время выполнения.

Приведенный ниже код приводит к сообщению об ошибке «Превышено максимальное время выполнения». Если я уменьшу число итераций (3), это будет работать. Но мне нужно перебрать примерно 20 тыс. Строк.

function myFunction(){
  var url = '<<file name>>';
  var bggXml = UrlFetchApp.fetch(url).getContentText();

  var document = XmlService.parse(bggXml);
  var root = document.getRootElement();
  var now = new Date();



  for(var i = 0; i <= 20; i++){


  var shopitem = root.getChildren('SHOPITEM')[i];

  var code = shopitem.getChild('CODE').getText();
  var stock100 = shopitem.getChild('STOCK').getChild('WAREHOUSES').getChildren('WAREHOUSE')[0].getChild('VALUE').getText();
  var stock801 = shopitem.getChild('STOCK').getChild('WAREHOUSES').getChildren('WAREHOUSE')[1].getChild('VALUE').getText();




  SpreadsheetApp.getActiveSheet().getRange(1+i,1).setValue(code);
  SpreadsheetApp.getActiveSheet().getRange(1+i,2).setValue(stock100);
  SpreadsheetApp.getActiveSheet().getRange(1+i,3).setValue(stock801);


 } 


}

Структура фида

<SHOP>
    <SHOPITEM>
        <CODE>#SKU#</CODE>
        <STOCK>
            <WAREHOUSES>
                <WAREHOUSE>
                    <NAME>Sklad 100</NAME>
                    <VALUE>"stock value"</VALUE>
                </WAREHOUSE>
                <WAREHOUSE>
                    <NAME>Sklad 801</NAME>
                    <VALUE>"stock value"</VALUE>
                </WAREHOUSE>
            </WAREHOUSES>
        </STOCK>
    </SHOPITEM>
</SHOP>

Любое предложение, что может быть не так?

Большое спасибо

1 Ответ

0 голосов
/ 18 марта 2020

Как говорится в сообщении об ошибке, вы достигли предела времени выполнения скрипта, который может составлять 6 или 30 минут в зависимости от типа вашей учетной записи, как указано здесь .

Чтобы избежать этого, вы можете сделать две вещи (не взаимоисключающие):

Повысить эффективность кода:

Повысить эффективность вашего кода. Вы можете, например, заменить разные setValue на одно единственное setValues. Вам придется заменить это:

SpreadsheetApp.getActiveSheet().getRange(1+i,1).setValue(code);
SpreadsheetApp.getActiveSheet().getRange(1+i,2).setValue(stock100);
SpreadsheetApp.getActiveSheet().getRange(1+i,3).setValue(stock801);

На это:

SpreadsheetApp.getActiveSheet().getRange(1+i, 1, 1, 3).setValues([[code, stock100, stock801]]);

Разбить скрипт на несколько исполнений:

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

  • Узнайте, сколько итераций вы можете выполнить, прежде чем достигните предела времени (в приведенном ниже примере это значение равно 3). Каждое выполнение должно будет выполнить это количество итераций до завершения.

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

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

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

function myFunction(){
  var i_old = // Retrieve i stored in previous execution (from PropertiesService? Spreadsheet?) (should be 0 if first execution)
  var n_int = 3 // Number of iterations that can be done in a single execution without reaching time limit (change accordingly)
  var total = 20 // Total number of iterations (change accordingly)
  var url = '<<file name>>';
  var bggXml = UrlFetchApp.fetch(url).getContentText();
  var document = XmlService.parse(bggXml);
  var root = document.getRootElement();
  var now = new Date();
  // Loop starts at previous i store until it reaches the specified number of iterations for one execution or reaches the total number:
  for(var i = i_old; i <= i_old + n_int && i <= total; i++) { 
    var shopitem = root.getChildren('SHOPITEM')[i];
    var code = shopitem.getChild('CODE').getText();
    var stock100 = shopitem.getChild('STOCK').getChild('WAREHOUSES').getChildren('WAREHOUSE')[0].getChild('VALUE').getText();
    var stock801 = shopitem.getChild('STOCK').getChild('WAREHOUSES').getChildren('WAREHOUSE')[1].getChild('VALUE').getText();
    SpreadsheetApp.getActiveSheet().getRange(1 + i, 1, 1, 3).setValues([[code, stock100, stock801]]);
  }
  // Store i somewhere (PropertiesService? Spreadsheet?)
  if (i <= total) { // Create trigger if i hasn't reach the total number of iteration
    ScriptApp.newTrigger("myFunction")
    .timeBased()
    .after(1000 * 60) // This fires the function 1 minute after the current execution ends. Change this time according to your preferences
    .create();  
  }
}

Ссылка:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...