我在使用 TypeScript 为 Node.js 环境编写的 firebase 函数时遇到了问题。我有一个带有 https-endpoint 的函数,客户端可以在其中发送需要存储在数据库中的数据。为了知道哪些对象已经被添加到数据库中,它首先读取一个路径(“lookup”),该路径具有对象的简化注册表(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.log("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 应用程序调用该函数时,它返回一个“内部”-error
当我在云控制台中查看功能日志时,我看到以下错误:
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
处发生了一些事情。正如我从 this SO question 中读到的那样同时读取和写入同一位置似乎是一个问题。但我很确定我不会在这里这样做......此外,除了实际错误之外,一切似乎都表现得像它应该的那样。
更新 combinedValues
时,它是一个具有约 300 个键/值对的对象,这是个问题吗?
最佳答案
看起来您的函数内存不足,每个云函数都为其执行分配了内存。 您可以尝试将堆栈大小从其默认值 (256MB) 增加到 2GB,方法是: Functions-> Dashboard,然后转到您有问题的功能,然后单击右侧菜单“Detailed usage stats”:
然后在谷歌云仪表板中的函数详细信息上单击编辑:
注意:您应该记住,当您的数据增长时,您可能会超过最高限制,因此在云函数中查询时请考虑这一点
关于node.js - Firebase 函数在 Function.MapValues 处返回 RangeError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50411141/