【问题标题】:Listening to Firebase database in AWS Lambda times out在 AWS Lambda 中侦听 Firebase 数据库超时
【发布时间】:2017-01-22 04:37:30
【问题描述】:

我正在构建 Alexa 技能,这需要我收听 Firebase 实时数据库。在该技能的一个特定部分中,我需要向 Firebase 写入一个 JSON 对象,该对象由两个字段组成,“intent”,具有一个无关紧要的值,“done”,其值为false

然后,我等待另一个侦听此数据库的设备注册此更改,此时它会创建另一个名为“result”的字段,其中包含一些数值,并将“done”的值更改为 true。

那么原函数(test1)应该识别“done”的值为真,然后检索“result”的值。

我遇到的问题是想出一个函数,该函数在我的主(异步)函数完成之前执行所有这些读/写操作。正如标题所示,AWS Lambda 出于某种原因超时,我无法读取“结果”的值。

这是我正在使用的功能:

function test1(intentName, targetRef, context) {
    console.log("writing");
    targetRef.set({
        intent: intentName,
        done: false
    }).then(function() {
        return targetRef.orderByChild("done").equalTo(true).on("value");
    }).then(function(snapshot) {
        var res = snapshot.val().result;
        console.log("Res: " + res);
        context.succeed( //context.succeed should be called after "result" has a value.
            generateResponse(
                buildSpeechletReponse("The result is" + processNumbersForSpeech(res), true),
                {}
            )
        );
    });
}

这是控制台的输出(在 AWS Lambda 中):

    
20:05:31
START RequestId: a25d2354-d9cb-11e6-b80a-f35142a5f45f Version: $LATEST
20:05:31
2017-01-13T20:05:31.464Z    a25d2354-d9cb-11e6-b80a-f35142a5f45f    writing

20:05:35
END RequestId: a25d2354-d9cb-11e6-b80a-f35142a5f45f

20:05:35
REPORT RequestId: a25d2354-d9cb-11e6-b80a-f35142a5f45f  Duration: 4001.15 ms    Billed Duration: 4000 ms Memory Size: 128 MB    Max Memory Used: 39 MB

20:05:35
2017-01-13T20:05:35.335Z a25d2354-d9cb-11e6-b80a-f35142a5f45f Task timed out after 4.00 seconds

以下是 Firebase 数据的结构:

“完成”最初是错误的。当其他设备添加“result”时,它也会将“done”的值更新为true。 “148434459...”是 targetRef。

非常感谢您的帮助。如果需要,我会提供更多信息。

【问题讨论】:

标签: javascript amazon-web-services firebase firebase-realtime-database aws-lambda


【解决方案1】:

问题是on 没有返回承诺。相反,它返回作为参数传递的回调函数。 on 将为初始数据调用回调,然后为对数据所做的任何更改再次调用。

你很可能想使用once,它确实会返回一个承诺:

...
}).then(function () {
    return targetRef.orderByChild("done").equalTo(true).once("value");
}).then(function (snapshot) {
    snapshot.forEach(function (childSnapshot) {
        console.log(childSnapshot.val());
    });
})
...

请注意,promise 的已解析快照将包含零个或多个与查询匹配的子项。要枚举孩子,可以使用快照的forEach 方法。

【讨论】:

  • 当我这样做时,控制台会打印:“Unread: null”,然后是“FIREBASE WARNING: Using an unspecified index。考虑在 targetRef 添加“.indexOn”:“done”到您的安全规则为了更好的性能
  • 更新了答案以显示如何枚举匹配的孩子。在快照上调用 val() 会返回一个包含子键和值的对象 - 因此其中没有 result 键。警告是因为您没有为查询中使用的子属性 (done) 编制索引。为此,请参阅docs
  • 我有点困惑......那么我能读取“结果”的值吗?而且,当我调用console.log(childSnapshot.val()) 时,没有输出。
  • 看看控制台输出,它应该是有道理的。我想它是childSnapshot.val().result,但您的问题并没有使您的数据库结构清晰。另外,添加console.log(snapshot.val()) 以查看您是否有任何匹配的孩子。
  • 我尝试在 console.log(childSnapshot.val()) 之前调用 console.log("hello"),但它也没有输出“hello”。我不知道为什么,但它似乎没有执行 forEach 块。
【解决方案2】:

我发现在 lambda 函数(例如通过 firebase-admin)中初始化 firebase 会阻止函数终止(直到默认的 6 秒超时),除非您在 firebase 应用实例上调用 app.delete()。此外,您应确保每次运行 lambda 函数时都使用新的 firebase 应用程序实例,否则您会遇到问题。

const app = admin.initializeApp({});
app.database().ref('child').set('hello').then(() => {
  return app.delete();
}).then(() => {
  let response = {}; // whatever
  callback(null, response);
});

【讨论】:

  • 我明白了……这很有趣。即使我不使用 firebase-admin 这也适用吗?
  • 另外,“使用新的 Firebase 应用实例”是什么意思?我应该在每次运行 lambda 函数之前调用firebase.initializeApp(config) 吗?目前,我没有这样做。
  • @MikiP 我认为问题的症结在于initializeApp(无论是否使用 firebase-admin)与 firebase 建立了持久连接,从而阻止 lambda 进程退出,除非连接通过app.delete()。所以你需要清理你的firebase连接。是的,你应该每次在你的lamba函数中调用initializeApp,否则如果你在函数上下文之外初始化firebase,你可能会遇到“这个应用程序已被删除”错误。
  • 我明白了。非常感谢您的帮助。
【解决方案3】:

您的 Lambda 函数可能会在 4 秒后超时,因为您在配置 Lambda 函数时设置了此值。为了让您的函数等待外部事情发生,您可以安排一个函数定期使用 setTimeout() 查询该值,直到该值存在。如果这需要超过 4 秒,您还需要增加函数超时时间。

【讨论】:

  • 不幸的是,我尝试将超时设置为 20 秒以上,但没有帮助。在 Firebase 控制台中,我看到“结果”会在不到一秒的时间内出现。
【解决方案4】:

来自 AWS Lambda 文档:

问:AWS Lambda 函数可以执行多长时间?

对 AWS Lambda 的所有调用必须在 300 秒内完成执行。默认超时为 3 秒,但您可以将超时设置为 1 到 300 秒之间的任何值。

我建议您在尝试从 Lambda 函数内部等待 Firebase 事件时会遇到问题。 Lambda 被设计为使用数据调用并处理数据并退出,而不是等待其他事件发生。你最好使用某种 VPS 并运行一个通用的 Node 进程来完成数据库工作。 Lambda 将数据推送到 Firebase 很好,但您尝试使用 Firebase 实现的目标可能是错误的方法。

【讨论】:

  • 好的。我只是尝试设置 2 秒的超时时间,然后在此之前使用“结果”更新了 Firebase。这还有问题吗?
【解决方案5】:

您在调用另一个函数之前调用该函数。试试 npm sleep() 或 setTimeout() 让你的函数暂停一下。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-06
    • 2020-07-30
    • 2023-03-08
    • 1970-01-01
    • 2020-03-05
    相关资源
    最近更新 更多