Я пишу надстройку Google Sheets, которая копирует некоторые данные из одной электронной таблицы в другую, а затем переформатирует их. Используемые наборы данных часто бывают большими (~ 100 тыс. Строк), поэтому, чтобы избежать превышения 6-минутного предела тайм-аута, я разбиваю данные на фрагменты, а затем запускаю функцию копирования данных параллельно для каждого фрагмента, используя вызовы google.script.run из на стороне клиента.
В моем наборе данных из ~ 100 тыс. строк первая пара фрагментов, которые необходимо завершить, успешно копируются, а остальные выдают ошибку «Время ожидания электронных таблиц службы истекло при доступе к документу с идентификатором [электронная таблица id]. "
А вот как это выглядит на панели инструментов Apps Script:
Меня сбивают с толку ошибки тайм-аута, потому что:
- Я успешно запустил скрипт для набора данных, который содержит 5000 строк
- Панель инструментов скрипта приложений показывает, что выполнения завершились с ошибкой до 6 минут (скорее, 4-5 минут)
- Ведение журнала панели инструментов скрипта приложений показывает успешное ведение журнала неудачных (тайм-аут) выполнений. Регистрация происходит после операции setValues () (см. Код ниже); единственное, что происходит после регистрации, - это возврат, поэтому я не понимаю, как он мог успешно войти в журнал, а затем время ожидания (я думал, что скрипт приложений был синхронным ... но, может быть, я ошибаюсь?)
Я также не уверен в этих «неперехваченных» ошибках, но они, похоже, отображаются на панели управления как «Документ [идентификатор электронной таблицы] отсутствует (возможно, он был удален или у вас нет доступа для чтения ?) "
Это документ, в который я копирую, и я подтвердил, что он все еще существует на моем Диске, и я могу открыть и просмотрите данные, которые были успешно скопированы. Может ли документ go «отсутствовать», если слишком много экземпляров скрипта пытаются получить к нему доступ одновременно?
Я экспериментировал с меньшими размерами блоков (1000 и 2000 строк) и получал те же типы ошибок .
Вот как выглядит мой Javascript на стороне клиента:
// This function is the success handler that runs after another function (which grabs the total # of rows
// from the sheet to be copied, and then creates the new spreadsheet to be copied into) completes
function dataParamsSuccess(dataParameters) {
// dataParameters = [busHrs, outputSsUrl, lastRow, maxRows, maxColumns]
var busHrs = dataParameters[0];
var outputSsUrl = dataParameters[1];
var lastRow = dataParameters[2];
var maxRows = dataParameters[3];
var maxColumns = dataParameters[4];
console.log(maxRows);
console.log(maxColumns);
// Set chunk size
var chunkSize = 5000; // number of rows in chunk
// Determine number of chunks
var numChunks = Math.ceil(lastRow / chunkSize);
var lastChunkSize = lastRow % chunkSize;
if ((numChunks-1) * chunkSize + lastChunkSize == lastRow) {
console.log("Math checks out");
} else {
console.log("oops, check your math");
}
// Generate status message
var statusHtml = numChunks + " chunks to be copied";
for (i=0; i<numChunks; i++) {
var chunkNum = i+1;
var chunkNumStr = chunkNum.toString();
statusHtml += "<div id=\"chunk" + chunkNumStr + "Status\"></div>";
}
document.getElementById("statusMsg").innerHTML = statusHtml;
var startRow = 1;
// Call copyData once for each chunk
for (i=0; i<numChunks; i++) {
var chunkNum = i+1;
var chunkNumStr = chunkNum.toString();
var chunkDivId = "chunk" + chunkNumStr + "Status";
if (chunkNum==numChunks) { // if this is the last chunk, chunk size is smaller
chunkSize = lastChunkSize;
}
var copyParams = [chunkNum, chunkSize, startRow, outputSsUrl];
google.script.run
.withSuccessHandler(copyChunkSuccess)
.copyData(copyParams);
document.getElementById(chunkDivId).innerHTML = "Chunk " + chunkNumStr + " copying in progress";
startRow += chunkSize;
console.log("startRow: " + startRow.toString());
}
// Haven't gotten to the part where I figure out what to do after all chunks are complete yet
}
А вот вызываемая функция скрипта приложений на стороне сервера:
function copyData(copyParams) {
try {
// copyParams = [chunkNum, chunkSize, startRow, outputSsUrl]
var chunkNum = copyParams[0];
var chunkSize = copyParams[1];
var startRow = copyParams[2];
var outputSsUrl = copyParams[3];
var lastRow = startRow + chunkSize;
// Get input and output sheets
var dataSheet = SpreadsheetApp.getActiveSheet();
var outputSpreadsheet = SpreadsheetApp.openByUrl(outputSsUrl);
var outputSheet = outputSpreadsheet.getActiveSheet();
// Copy values
var values = dataSheet.getRange(startRow, 1, chunkSize, 22).getValues();
outputSheet.getRange(startRow, 1, chunkSize, 22).setValues(values);
// Logging
var dataSpreadsheetId = dataSheet.getParent().getId();
var outputSpreadsheetId = outputSpreadsheet.getId();
console.log("Chunk " + chunkNum.toString() + " (rows " + startRow.toString() + " through " + lastRow.toString() + ") copied successfully");
return [chunkNum, startRow, lastRow, "success"];
} catch(e) {
return [chunkNum, startRow, lastRow, e.message]; // Return error to client-side; server-side logging is taking too long
}
}