Оптимизируйте Google Scripts - триггеры не работают - PullRequest
1 голос
/ 03 мая 2019

Задача

Мои триггеры Google Script не работают, потому что он "использует слишком много процессорного времени", согласно сообщениям об ошибках, которые я получаю. Как я могу оптимизировать свои скрипты, чтобы использовать меньше процессорного времени? Я разделил sortGsheetFiles на другой триггер, но он все еще занимает много времени. Раньше он сочетался с функцией importXLSXtoGsheet.

Сценарии объяснены

У меня есть 52 папки, каждая из которых содержит один файл электронной таблицы.
Каждая папка доступна для разных коллег. В течение дня люди вносят изменения в файлы.

  1. В конце дня все файлы собираются в одну папку (gsheetFolder) и преобразуются в файлы XLSX с использованием функции collectAndExportXLS.

Эти файлы вечером копируются на локальный сервер (с использованием пакетного сценария и синхронизации диска), который обновляет другую информацию в файле и копируется обратно в importXLSXfolder.

  1. Утром запускается функция importXLSXtoGsheet и конвертирует все файлы XLSX в папке importXLSXfolder в файлы Gsheet в gsheetFolder.
  2. После этого sortGsheetFiles запускается, сортируя и перемещая каждый файл Gsheet в одну из 52 папок (используя список массивов из текущей электронной таблицы).

Другие действия включают очистку папок с помощью функции deleteFolder.

Триггеры

importXLSXtoGsheet - каждый день - с 6 до 7 утра
sortGsheetFiles - каждый день - с 7 до 8 утра
collectAndExportXLS - каждый день - с 22:00 до 23:00.

Сценарий

var gsheetFolder = 'xxx';
var XLSXfolder = 'xxxxx';
var importXLSXfolder = 'xxxxx';

function checkEmptyFolder() {

var folders = DocsList.getAllFolders()
  for(n=0;n<folders.length;++n){
    if(folders[n].getFiles().length==0 && folders[n].getFolders().length==0){
     folders[n].setTrashed(true)
     Logger.log(folders[n].getName())
     }
   }  
}

function importXLSXtoGsheet(){

// ========= convert all XLS files in XLS folder to GSheet and put in the general gsheet folder - after that sort in gsheet filiaal folders =========
// cleanup exportXLS folder first 
  deleteFolder(XLSXfolder);

  var files = DriveApp.getFolderById(importXLSXfolder).searchFiles('title contains ".xlsx"');
  while(files.hasNext()) {
    var xFile = files.next();
    var name = xFile.getName();
    if (name.indexOf('.xlsx')) { 
      var ID = xFile.getId();
      var xBlob = xFile.getBlob();
      var newFile = {
        title : name + ('.xlsx'),
        key : ID,
        parents: [{"id": gsheetFolder}]
      }
      file = Drive.Files.insert(newFile, xBlob, {convert: true});
    }
  }
  deleteFolder(importXLSXfolder);
}

function sortGsheetFiles() {

  // ========= sort Gsheet folder and move to corresponding filiaal folders =========

  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheets()[0];
  var myArrayFileName = sheet.getRange("A2:A53").getValues();
  var myArrayFolderId = sheet.getRange("B2:B53").getValues();
  var a = myArrayFileName.join().split(',').filter(Boolean);
  var b = myArrayFolderId.join().split(',').filter(Boolean);

  var folderId = gsheetFolder;
  // Log the name of every file in the folder. 
  var files = DriveApp.getFolderById(folderId).getFiles();

     while (files.hasNext()) {
      var file = files.next();
        for (var i in a) {
          var id = file.getId();
          if (file.getName() == a[i]) { 
            moveFiles(id, b[i]); // Match found and move to corresponding folder
          }
        }
     }
  deleteFolder(importXLSXfolder);
}

function collectAndExportXLS() {
  // ========= collect all Gsheet files, copy to gsheet folder and convert to xlsx and move to xlsx folder =========

  // cleanup gsheet folder
  deleteFolder(gsheetFolder);

  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheets()[0];
  var myArrayFileName = sheet.getRange("A2:A53").getValues();
  var myArrayFolderId = sheet.getRange("B2:B53").getValues();
  var a = myArrayFileName.join().split(',').filter(Boolean);
  var b = myArrayFolderId.join().split(',').filter(Boolean);

  var folderId = gsheetFolder;

  for (var i in b) {
  var files = DriveApp.getFolderById(b[i]).getFiles();
    while (files.hasNext()) {
      var file = files.next();
      var id = file.getId();
      moveFiles(id , folderId);
    }
  }
  ConvertBackToXLS()
  deleteFolder(gsheetFolder);

}

function moveFiles(sourceFileId, targetFolderId) {
  var file = DriveApp.getFileById(sourceFileId);
  file.getParents().next().removeFile(file);
  DriveApp.getFolderById(targetFolderId).addFile(file);
}

function deleteFolder(folder) {
  //delete files in a folder without sending to trash!

  var eachFile, idToDLET, myFolder, rtrnFromDLET, thisFile, files;
  files = DriveApp.getFolderById(folder).getFiles();

  while (files.hasNext()) {//If there is another element in the iterator
    eachFile = files.next();
    idToDLET = eachFile.getId();
    //Logger.log('idToDLET: ' + idToDLET);

    rtrnFromDLET = Drive.Files.remove(idToDLET);
  };
   Logger.log('folder deleted');
}

function ConvertBackToXLS() {

  // Log the name of every file in the folder.
  var files = DriveApp.getFolderById(gsheetFolder).getFiles();
  var dir = DriveApp.getFolderById(XLSXfolder);
  while (files.hasNext()) {

     try {
     var file = files.next(); 
     var ss = SpreadsheetApp.openById(file.getId());
     Logger.log(file.getId());
     var url = "https://docs.google.com/feeds/download/spreadsheets/Export?key=" + file.getId() + "&exportFormat=xlsx";
     var params = {
      method      : "get",
      headers     : {"Authorization": "Bearer " + ScriptApp.getOAuthToken()},
      muteHttpExceptions: true
    };

    var blob = UrlFetchApp.fetch(url, params).getBlob();
    blob.setName(ss.getName());  
    var newfile = dir.createFile(blob); 

  } catch (f) {
    Logger.log(f.toString());
  }
 }
}

1 Ответ

1 голос
/ 04 мая 2019

Как насчет этой модификации?Пожалуйста, подумайте об этом как один из нескольких ответов.

И, что важно, пожалуйста, протестируйте сценарий, используя тестовую ситуацию, прежде чем приступить к реальной ситуации.

О вашем сценарии:

  1. collectAndExportXLS(): Что касается названия этой функции, я не изменял collectAndExportXLS().Потому что я подумал, что вы можете использовать это имя функции в другом сценарии или триггерах.

    1. Удалить все файлы в gsheetFolder.
    2. Конвертировать таблицу Google в каждой папке ID, полученный из«B2: B53» листа с первым индексом в активной электронной таблице в формате XLSX.
      • Имя файла похоже на sample.xlsx.
      • Все преобразованные файлы помещаются в XLSXfolder.
    3. Удалите все файлы во всех идентификаторах папок.
    4. XLSX-файлы в XLSXfolder заносятся в importXLSXfolder другим скриптом.
  2. importXLSXtoGsheet(): имя этой функцииЯ не изменил collectAndExportXLS().Потому что я подумал, что вы можете использовать это имя функции в других скриптах или триггерах.

    1. Удалить все файлы в XLSXfolder.
    2. Конвертировать все файлы XLSX в importXLSXfolder в GoogleSpreadsheet.
      • Имя файла похоже на sample.xlsx.
      • Преобразованные таблицы Google помещаются в gsheetFolder.
    3. Удалите все файлы в importXLSXfolder.
  3. sortGsheetFiles()

    1. Переместите электронные таблицы Google в gsheetFolder в каждый идентификатор папки, полученный из «B2: B53» листа с 1-миндекс в активной электронной таблице.
      • Чтобы сопоставить идентификатор папки, имена файлов электронной таблицы Google и значения, полученные из "A2: A53".
    2. Удалить все файлы в importXLSXfolder.
  4. Я понял, что из вашего вопроса имена файлов столбца "A2: A53" активной электронной таблицы совпадают с именами файлов электронных таблиц Google, которые были помещены в папкиидентификаторов папок столбца «B2: B53».

  5. Я понял, что количество всех файлов меньше 100.

Я понимаю, как выше.Если мое понимание верно, как насчет этой модификации?В моей модификации я использовал пакетный запрос Drive API и метод fetchAll UrlFetchApp с типом multipart/form-data для вашей ситуации.Пакетный запрос и метод fetchAll могут работать с асинхронным процессом.Таким образом я подумал, что стоимость вашего процесса может быть уменьшена.

Чтобы использовать эти методы, я использовал 2 библиотеки GAS.Прежде чем запускать скрипт, пожалуйста, установите эти 2 библиотеки для вашего скрипта.Вы можете увидеть, как установить библиотеку, следующим образом.

  1. Установить библиотеку для запуска метода fetchAll UrlFetchApp с типом multipart/form-data.
  2. Установить библиотеку для запуска пакетного запроса.

Точки изменения:

  • collectAndExportXLS()

    • Идентификаторы файлов в каждой папке извлекаются с помощью пакетного запроса.
    • Капли (в формате XLSX) из каждого идентификатора файла извлекаются методом fetchAll в UrlFetchApp.
    • Файлы формата XLSX создаются FetchApp..
  • importXLSXtoGsheet()

    • Список файлов извлекается с помощью метода files.list Drive API.
    • ФайлыФормат XLSX преобразуется в электронную таблицу Google с помощью пакетного запроса.
  • sortGsheetFiles()

    • Список файлов извлекается методом files.list изDrive API.
    • Файлы электронной таблицы Google перемещаются в каждый идентификатор папки, полученный из столбца «B2: B53» активного Sпредварительный лист с использованием пакетного запроса.
  • deleteFolder()

    • Файлы в папке удаляются пакетным запросом.

Когда в вашем сценарии отражены вышеуказанные точки, он становится следующим:

Модифицированный скрипт:

После установки 2 библиотек, пожалуйста, запустите следующий скрипт.

var gsheetFolder = '###';
var XLSXfolder = '###';
var importXLSXfolder = '###';

// Modified
function deleteFolder(folderId) {
  var url = "https://www.googleapis.com/drive/v3/files?q='" + folderId + "'+in+parents+and+trashed%3Dfalse&fields=files%2Fid&access_token=" + ScriptApp.getOAuthToken();
  var res = UrlFetchApp.fetch(url);
  var obj = JSON.parse(res.getContentText());
  var reqs = obj.files.map(function(e) {return {method: "DELETE", endpoint: "https://www.googleapis.com/drive/v3/files/" + e.id}});
  var requests = {batchPath: "batch/drive/v3", requests: reqs};
  if (requests.requests.length > 0) BatchRequest.Do(requests);
}

// Added
function deleteFiles(files) {
  var reqs = files.map(function(e) {return {method: "DELETE", endpoint: "https://www.googleapis.com/drive/v3/files/" + e.id}});
  var requests = {batchPath: "batch/drive/v3", requests: reqs};
  if (requests.requests.length > 0) BatchRequest.Do(requests);
}

// Added
function getValuesFromSpreadsheet() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheets()[0];
  return sheet.getRange("A2:B53").getValues();
}

// Modified
function sortGsheetFiles() {
  var url = "https://www.googleapis.com/drive/v3/files?q='" + gsheetFolder + "'+in+parents+and+mimeType%3D'" + MimeType.GOOGLE_SHEETS + "'+and+trashed%3Dfalse&fields=files(id%2Cname)&access_token=" + ScriptApp.getOAuthToken();
  var res = UrlFetchApp.fetch(url);
  var obj = JSON.parse(res.getContentText());
  var values = getValuesFromSpreadsheet();
  var reqs = values.reduce(function(ar, e) {
    for (var i = 0; i < obj.files.length; i++) {
      if (obj.files[i].name == e[0]) {
        ar.push({
          method: "PATCH",
          endpoint: "https://www.googleapis.com/drive/v3/files/" + obj.files[i].id + "?addParents=" + e[1] + "&removeParents=" + gsheetFolder,
        });
        break;
      }
    }
    return ar;
  }, []);
  var requests = {batchPath: "batch/drive/v3", requests: reqs};
  if (requests.requests.length > 0) BatchRequest.Do(requests);
  deleteFolder(importXLSXfolder);
}

// Modified
function importXLSXtoGsheet(){
  deleteFolder(XLSXfolder);
  var url = "https://www.googleapis.com/drive/v3/files?q='" + importXLSXfolder + "'+in+parents+and+mimeType%3D'" + MimeType.MICROSOFT_EXCEL + "'+and+trashed%3Dfalse&fields=files(id%2Cname)&access_token=" + ScriptApp.getOAuthToken();
  var res = UrlFetchApp.fetch(url);
  var obj = JSON.parse(res.getContentText());
  var reqs = obj.files.map(function(e) {return {
      method: "POST",
      endpoint: "https://www.googleapis.com/drive/v3/files/" + e.id + "/copy",
      requestBody: {mimeType: MimeType.GOOGLE_SHEETS, name: e.name + ".xlsx", parents: [gsheetFolder]},
    }
  });
  var requests = {batchPath: "batch/drive/v3", requests: reqs};
  if (requests.requests.length > 0) BatchRequest.Do(requests);
  deleteFolder(importXLSXfolder);
}

// Modified
function ConvertBackToXLS(fileList) {
  var token = ScriptApp.getOAuthToken();
  var reqs1 = fileList.map(function(e) {return {
      method: "GET",
      url: "https://docs.google.com/spreadsheets/export?id=" + e.id + "&exportFormat=xlsx&access_token=" + token,
    }
  });
  var res = UrlFetchApp.fetchAll(reqs1);
  var reqs2 = res.map(function(e, i) {
    var metadata = {name: fileList[i].name, parents: [XLSXfolder]};
    var form = FetchApp.createFormData(); // Create form data
    form.append("metadata", Utilities.newBlob(JSON.stringify(metadata), "application/json"));
    form.append("file", e.getBlob());
    var url = "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart";
    return {url: url, method: "POST", headers: {Authorization: "Bearer " + token}, body: form};
  });
  FetchApp.fetchAll(reqs2);
}

// Modified
function collectAndExportXLS() {
  deleteFolder(gsheetFolder);
  var values = getValuesFromSpreadsheet();
  var reqs1 = values.reduce(function(ar, e) {
    if (e[0] && e[1]) {
      ar.push({
        method: "GET",
        endpoint: "https://www.googleapis.com/drive/v3/files?q='" + e[1] + "'+in+parents+and+trashed%3Dfalse&fields=files(id%2Cname)",
      });
    }
    return ar;
  }, []);
  var resForReq1 = BatchRequest.Do({batchPath: "batch/drive/v3", requests: reqs1});
  var temp = resForReq1.getContentText().split("--batch");
  var files = temp.slice(1, temp.length - 1).map(function(e) {return JSON.parse(e.match(/{[\S\s]+}/g)[0])});
  var fileList = files.reduce(function(ar, e) {return ar.concat(e.files.map(function(f) {return f}))}, []);
  ConvertBackToXLS(fileList);
  deleteFiles(fileList);
}

Примечание:

  • В этой модификации обработка ошибок не отражается, потому что я не смог проверить вашу ситуацию.Поэтому, пожалуйста, добавьте его, если вам необходимо.
  • Если размер файла XLSX большой, может возникнуть ошибка.

Ссылки:

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