Firebase 函数在 Function.MapValues 处返回 RangeError

Posted

技术标签:

【中文标题】Firebase 函数在 Function.MapValues 处返回 RangeError【英文标题】:Firebase functions returns RangeError at Function.MapValues 【发布时间】:2018-10-28 21:13:47 【问题描述】:

我遇到了一个使用 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 应用程序调用该函数时,它返回一个 "Internal"-error

当我在云控制台中查看函数日志时,我看到以下错误:

assignment-scrapeAssignments uolk47opctna 未处理的错误 RangeError: Function.mapValues 超出最大调用堆栈大小 (/user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:13395:23) 在编码 (/user_code/node_modules/firebase-functions/lib/providers/https.js:204:18) 在 /user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:13400:38 在 /user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:4925:15 在 baseForOwn (/user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:3010:24) 在 Function.mapValues (/user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:13399:7) 在编码 (/user_code/node_modules/firebase-functions/lib/providers/https.js:204:18) 在 /user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:13400:38 在 /user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:4925:15 在 baseForOwn (/user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:3010:24) 在 Function.mapValues (/user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:13399:7)

我能读到的只是它是一个“RangeError:超出最大调用堆栈大小”-错误,并且在Function.mapValues 发生了一些事情。正如我从this SO question 中看到的那样,同时读取和写入同一位置似乎是一个问题。但我很确定我不会在这里这样做。除了实际错误之外,一切似乎都表现得像它应该的那样。

combinedValues 更新时,它是一个有大约300 个键/值对的对象,这是个问题吗?

【问题讨论】:

【参考方案1】:

您的函数似乎内存不足,每个云函数都为其执行分配了内存。 您可以尝试将堆栈大小从其默认值 (256MB) 增加到 2GB,方法是: Functions-> Dashboard,然后进入你有问题的函数,点击右侧菜单“Detailed usage stats”:

然后在谷歌云仪表板中的功能详细信息上单击编辑:

然后将“分配的内存”的值增加到 2GB(或更低的足够值):

注意:您应该记住,当您的数据增长时您可能会超过最高限制,因此在云函数中查询时请考虑这一点

【讨论】:

以上是关于Firebase 函数在 Function.MapValues 处返回 RangeError的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Firebase Cloud 函数中调用导出的 https Firebase Cloud 函数?

如何使用firebase函数返回保存在firebase存储中的文件的json内容

如何在 firebase 托管的 webapp 中获取 firebase 函数 URL?

Firebase 函数执行和订阅由 firebase 函数更新的列表

无法在 razorpay [firebase_functions/internal] 内部的 firebase 云函数中创建订单 ID

Firebase 可调用函数未接收参数