Функции Firebase - получение файлов из облачного хранилища Google приводит к RangeError: превышен максимальный размер стека вызовов - PullRequest
1 голос
/ 09 марта 2020

Я пытаюсь получить файлы резервных копий Firestore из облачного хранилища Google, в котором они хранятся:

export const retrieveFirestoreBackup = functions.https.onCall(
  async (data: RetrieveFirestoreBackupPayload, context) => {
      try {
        return await storage.bucket(bucket).getFiles();
      } catch (error) {
        console.log("Error getting backup files.", error);
        throw new functionsInit.https.HttpsError("unknown", error);
      }
  }
);

Когда я использую свой эмулятор функций Firebase, все работает как положено. Но выполнение того же кода в развернутых функциях Firebase приводит к следующей ошибке:

Unhandled error RangeError: Maximum call stack size exceeded
    at isArrayLike (/srv/node_modules/lodash/lodash.js:11333:31)
    at keys (/srv/node_modules/lodash/lodash.js:13307:14)
    at /srv/node_modules/lodash/lodash.js:4900:21
    at baseForOwn (/srv/node_modules/lodash/lodash.js:2990:24)
    at Function.mapValues (/srv/node_modules/lodash/lodash.js:13400:7)
    at encode (/srv/node_modules/firebase-functions/lib/providers/https.js:179:18)
    at /srv/node_modules/lodash/lodash.js:13401:38
    at /srv/node_modules/lodash/lodash.js:4905:15
    at baseForOwn (/srv/node_modules/lodash/lodash.js:2990:24)
    at Function.mapValues (/srv/node_modules/lodash/lodash.js:13400:7)

Как успешно отправить файлы клиенту?

Ответы [ 2 ]

1 голос
/ 09 марта 2020

Просто публикую мой пересмотренный код, основанный на предложении Дуга Стивенсона, для тех, кому он нужен:

export const retrieveFirestoreBackup = functions.https.onCall(
  async (data: RetrieveFirestoreBackupPayload, context) => {
    try {
        const [files] = await storage.bucket(bucket).getFiles();
        const metadataArray = await Promise.all(
          files.map(file => {
            return file.getMetadata().then(result => result[0]);
          })
        );
        return metadataArray;
      } catch (error) {
        console.log("Error getting backup files.", error);
        throw new functionsInit.https.HttpsError("unknown", error);
      }
  }
);
1 голос
/ 09 марта 2020

Ваш код пытается сериализовать объект GetFilesResponse , возвращаемый getFiles() как JSON для отправки обратно вызывающей стороне. В документации API говорится, что это массив File объектов.

В сообщении об ошибке указывается, что объекты File слишком сложны для отправки с использованием стандартной сериализации JSON. Обратите внимание на документацию API, что каждый из них содержит объект Bucket, который, вероятно, содержит много других деталей реализации. Внимательно посмотрите на внутренние детали одного объекта File, если вы хотите понять его сложность. Возможно, все это помещается в память вашего компьютера, но не в ограниченную память, предоставляемую экземпляром сервера Cloud Functions.

Что вам, вероятно, следует вместо этого сделать, это просто перебрать массив объектов File из getFiles и создать новый массив только данных о файле, который вы хотите отправить обратно клиенту. Если все, что вам нужно, это путь к файлу, который сокращает ответ до простого массива строк, который должен быть в порядке для сегментов с ограниченным количеством файлов. Помните, что максимальный размер ответа Cloud Functions может составлять всего 10 МБ, поэтому для очень больших сегментов может возникнуть проблема.

...