Превышено максимальное время выполнения скриптов Google при консолидации данных GSheet

#google-apps-script

Вопрос:

Я работаю волонтером в местной средней школе искусств в южной Калифорнии. Я посмотрел видео на YouTube, чтобы написать сценарий, который поможет объединить данные отдельных учащихся в единую таблицу Google. В прошлом году он работал замечательно, однако теперь я получаю сообщение об ошибке «Превышено максимальное время выполнения».

Как я могу решить эту проблему? Текущий сценарий приведен ниже.

 function combineDataToMaster(){
    var folder        = DriveApp.getFolderById( "addfolderID123456789123456789" );
    var filesIterator = folder.getFiles();
    var file;
    var fileType;
    var ssID;
    var combinedData = [];
    var data;

    while( filesIterator.hasNext() ) { 
        file     = filesIterator.next();
        fileType = file.getMimeType();

        if( fileType === "application/vnd.google-apps.spreadsheet" ) {
            ssID = file.getId();
            data = getDataFromSpreadsheet(ssID);
            data = data.map( function( r ){ return r.concat( [ file.getName() ] ); } );
            data = data.map( function( r ){ return r.concat( file.getId()       ); } );

            combinedData = combinedData.concat( data );
        } //if ends here
    }//whileloop ends here

    var ws = SpreadsheetApp.getActiveSpreadsheet().getSheetByName( "Consolidated Sheets" );

    ws.getRange( "A2:L" ).clearContent();
    ws.getRange( 2, 1, combinedData.length, combinedData[ 0 ].length ).setValues( combinedData );
}

function getLastRowSpecial( range ){
    var rowNum = 0;
    var blank  = false;

    for( var row = 0; row < range.length; row   ) {
        if( range[ row ][ 0 ] === "" amp;amp; !blank ){
            rowNum = row;
            blank = true;
        } else if( range[ row ][ 0 ] !== "" ) {
            blank = false;
        };
    };

    return rowNum;
};

function getDataFromSpreadsheet( ssID ){
    var ss            = SpreadsheetApp.openById( ssID );
    var ws            = ss.getSheetByName( "Point Entry Form" );
    var columnToCheck = ws.getRange( "A5:A" ).getValues();
    var lastrow       = getLastRowSpecial( columnToCheck );
    var dataRange     = ws.getRange( 6, 1, lastrow, ws.getLastColumn() );
    var data          = dataRange.getValues();

    return data;
}
 

Комментарии:

1. В вашей ситуации, сколько файлов в папке?

2. От 150 до 200 учебных GSheets

3. Спасибо за ответ. Теперь я заметил, что ответ уже опубликован. В этом случае я хотел бы учесть существующий ответ.

Ответ №1:

Время выполнения скрипта Google Apps ограничено (6 минут).
Я столкнулся с той же проблемой и создал полезный класс для решения этой проблемы.

Перейдите в этот репозиторий и получите LongRun.gs и поместите его в свой проект (скопируйте и вставьте содержимое файла).
Затем измените combineDataToMaster() следующим образом. (Я написал комментарии, начинающиеся с [includeкат], где я его изменил)

 function combineDataToMaster(){
    var folder        = DriveApp.getFolderById( "addfolderID123456789123456789" );
    var filesIterator = folder.getFiles();
    var file;
    var fileType;
    var ssID;
    var combinedData = [];
    var data;

    // [inclu-cat] if you want to forcibly suspend the process to see what will happen, uncomment this.
    // LongRun.instance.setMaxExecutionSeconds(1);

    // [inclu-cat] get the index to resume(zero for the first time)
    // [inclu-cat] if it is first time, clear range first. otherwise find the row where to start pasting.
    let startIndex = LongRun.instance.startOrResume('combineDataToMaster');
    let index = 0;
    let pasteRow;
    var ws = SpreadsheetApp.getActiveSpreadsheet().getSheetByName( "Consolidated Sheets" );
    if ( startIndex == 0 ){
      ws.getRange( "A2:L" ).clearContent();
      pasteRow = 2;
    } 
    else {
      pasteRow = ws.getLastRow()   1;
    }   

    while( filesIterator.hasNext() ) { 
        file     = filesIterator.next();

        // [inclu-cat] skip until index == startIndex
        if (index < startIndex){
          index  ;
          continue;
        }

        // [inclu-cat] Each time before executing a process, you need to check if it should be stopped or not.
        if (LongRun.instance.checkShouldSuspend('combineDataToMaster', index)) {
          // if checkShouldSuspend() returns true, the next trigger has been set
          // and you should get out of the loop.
          console.log('*** The process has been suspended. ***');
          break;
        }

        fileType = file.getMimeType();

        if( fileType === "application/vnd.google-apps.spreadsheet" ) {
            ssID = file.getId();
            data = getDataFromSpreadsheet(ssID);
            data = data.map( function( r ){ return r.concat( [ file.getName() ] ); } );
            data = data.map( function( r ){ return r.concat( file.getId()       ); } );

            // [inclu-cat] Paste the data every time
            // combinedData = combinedData.concat( data );
            ws.getRange( pasteRow, 1, data.length, data[ 0 ].length ).setValues( data );
            pasteRow  = data.length;
        } //if ends here

        // [inclu-cat] increment counter
        index  ;

    }//whileloop ends here

    // [inclu-cat] you must always call end() to reset the long-running variables if there is no next trigger.
    LongRun.instance.end('combineDataToMaster');

    // [inclu-cat] these lines are moved
    // var ws = SpreadsheetApp.getActiveSpreadsheet().getSheetByName( "Consolidated Sheets" );
    // ws.getRange( "A2:L" ).clearContent();
    // ws.getRange( 2, 1, combinedData.length, combinedData[ 0 ].length ).setValues( combinedData );

}
 

Объяснение класса LongRun можно найти в этом блоге.

Комментарии:

1. Привет — Большое вам спасибо! Я ценю усилия, однако после тестирования предоставленного решения процесс приостанавливается (как и ожидалось), и данные больше не собираются. В окончательной консолидации отсутствует более 1 тыс. записей. Есть ли способ снова запустить скрипт с того места, где он остановился, чтобы не было потери данных? Спасибо!

2. Спасибо за тестирование. Сколько листов отсутствует? Если вы используете редактор сценариев приложений, не могли бы вы проверить панель выполнения (например, эту ) и есть ли какие-либо ошибки?

3. Привет — я проверил панель выполнения и никаких ошибок. Процесс выполнения, управляемый временем, не записывает данные в электронную таблицу объединенных данных. Есть предложения?

4. Спасибо за ваш ответ. Хм… Я запустил его для быстрого тестирования, и он сработал, поэтому я думаю, что может быть другая проблема. Однако без предоставления некоторых образцов ваших данных трудно найти причину. Если хотите, вы можете пообщаться со мной на Reddit, и я немного разберусь в этом. Моя учетная запись — это . (потому что я думаю, что было бы лучше избегать общения в разделе комментариев StackOverflow.)