У меня возникла проблема с функцией firebase, написанной на TypeScript для среды Node.js. У меня есть функция с https-endpoint, где клиент может отправлять данные, которые необходимо сохранить в базе данных. Чтобы узнать, какие объекты уже были добавлены в базу данных, он сначала считывает путь ("уважать"), который имеет упрощенный реестр объекта (lookup/:objectId/true). Затем он создает значения, которые должны быть обновлены по фактическому пути к объекту, и обновляет их в базе данных.
Функция следующая:
export const scrapeAssignments = functions.https.onCall((data, context) => {
const htmlString = data.htmlString
// const htmlString = fs.readFileSync(testPath.join(__dirname, "./assignmentListExample.html"), { encoding: 'utf8' })
if (!(typeof htmlString === 'string') || htmlString.length === 0) {
throw new functions.https.HttpsError('invalid-argument', 'The function must be called with one argument "htmlString"');
}
const userId = getUserIdFromCallableContext(context)
console.info("userId", userId)
let newAssignments: ScrapedAssignment[] = []
try {
newAssignments = parseAssignment(htmlString)
} catch (e) {
const error = <Error>e
throw new functions.https.HttpsError('not-found', 'parsing error: ' + error.message)
}
return admin.database().ref("lookup").child(userId).child("assignments")
.once("value", lookupSnapshot => {
const oldAssignmentsLookup = lookupSnapshot.val() || {}
const newAssignmentsLookup = makeLookup(newAssignments)
// 1. Create update values for scraped assignment data
let scrapedAssignmentUpdateValues = newAssignments.reduce((prev, current) => {
const prefixed = prefixObject(current.id + "/", current)
return { ...prev, ...prefixed }
}, {})
// 2. Use the diff from the two lookups to find old assignments to delete
const removeAssignmentsValues = {}
Object.keys(oldAssignmentsLookup).forEach(assignmentId => {
if (isUndefined(newAssignmentsLookup[assignmentId]))
removeAssignmentsValues[assignmentId] = null
})
// 3. Add other user values to newly found assignments
Object.keys(newAssignmentsLookup).forEach(assignmentId => {
if (isUndefined(oldAssignmentsLookup[assignmentId])) {
const doneKey = assignmentId + "/done"
scrapedAssignmentUpdateValues[doneKey] = false
}
})
const combinedValues = { ...scrapedAssignmentUpdateValues, ...removeAssignmentsValues }
return admin.database().ref("userAssignments").child(userId).update(combinedValues)
}).catch(reason => {
throw new functions.https.HttpsError('internal', 'Database reason: ' + reason)
})
})
Я вижу, что данные записываются в нужное место, и все, кажется, идет так, как ожидалось, за исключением того, что когда я вызываю функцию из приложения iOS, она возвращает ошибку "Внутренний"
Когда я проверяю журналы функций в облачной консоли, я вижу следующую ошибку:
assignment-scrapeAssignments uolk47opctna Unhandled error RangeError: Maximum call stack size exceeded at Function.mapValues (/user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:13395:23) at encode (/user_code/node_modules/firebase-functions/lib/providers/https.js:204:18) at /user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:13400:38 at /user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:4925:15 at baseForOwn (/user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:3010:24) at Function.mapValues (/user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:13399:7) at encode (/user_code/node_modules/firebase-functions/lib/providers/https.js:204:18) at /user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:13400:38 at /user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:4925:15 at baseForOwn (/user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:3010:24) at Function.mapValues (/user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:13399:7)
Все, что я могу прочитать, это то, что это ошибка «RangeError: превышен максимальный размер стека вызовов», и что-то происходит на Function.mapValues. Как я могу прочитать из этот ТАК вопрос, похоже, проблема с чтением и записью в одно и то же место в одно и то же время. Но я совершенно уверен, что здесь я этим не занимаюсь .. Плюс все вроде ведет себя так, как должно, за исключением самой ошибки.
Когда combinedValues обновляется, это объект с ~ 300 парами ключ / значение, это проблема?





Похоже, вашей функции не хватает памяти, каждая облачная функция выделила память для своего выполнения. Вы можете попробовать увеличить размер стека со значения по умолчанию (256 МБ) до 2 ГБ, перейдя по ссылке: Функции-> Панель управления, затем перейдите к проблемной функции и щелкните в правом меню «Подробная статистика использования»:
затем в сведениях о вашей функции на панели управления облаком Google нажмите редактировать:
затем увеличьте значение «выделенной памяти» до 2 ГБ (или ниже достаточного значения):
примечание: вы должны иметь в виду, что при росте объема данных вы можете превысить наивысший предел, поэтому учитывайте это при запросе в облачных функциях.