最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Listening to Firebase database in AWS Lambda times out - Stack Overflow

programmeradmin2浏览0评论

I'm building an Alexa Skill, which requires me to listen to a Firebase Realtime Database. In one particular part of the skill, I need to write a JSON object to Firebase, consisting of two fields, "intent", with an insignificant value, and "done", with a value of false.

Then, I wait for another device listening to this database to register this change, at which point it creates another field, named "result", with some numerical value, and changes the value of "done" to true.

Then the original function (test1) should recognize when the value of "done" is true, and then retrieve the value of "result".

What I'm having trouble with is ing up with a function that does all of these read/write operations before my main (asynchronous) function finishes. As the title suggests, AWS Lambda times out for some reason, and I am unable to read the value of "result".

This is the function I'm using:

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),
                {}
            )
        );
    });
}

This is the output of the console (in 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

The following is the structure of the Firebase data:

"done" is initially false. When the other device add "result", it also updates the value of "done" to true. "148434459..." is targetRef.

Your help is truly appreciated. I will supply more info if needed.

I'm building an Alexa Skill, which requires me to listen to a Firebase Realtime Database. In one particular part of the skill, I need to write a JSON object to Firebase, consisting of two fields, "intent", with an insignificant value, and "done", with a value of false.

Then, I wait for another device listening to this database to register this change, at which point it creates another field, named "result", with some numerical value, and changes the value of "done" to true.

Then the original function (test1) should recognize when the value of "done" is true, and then retrieve the value of "result".

What I'm having trouble with is ing up with a function that does all of these read/write operations before my main (asynchronous) function finishes. As the title suggests, AWS Lambda times out for some reason, and I am unable to read the value of "result".

This is the function I'm using:

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),
                {}
            )
        );
    });
}

This is the output of the console (in 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

The following is the structure of the Firebase data:

"done" is initially false. When the other device add "result", it also updates the value of "done" to true. "148434459..." is targetRef.

Your help is truly appreciated. I will supply more info if needed.

Share Improve this question edited Jan 13, 2017 at 22:39 Miki P asked Jan 13, 2017 at 20:45 Miki PMiki P 6521 gold badge9 silver badges22 bronze badges 1
  • Hope my answer here helps stackoverflow./a/45266181/2073325 – gchao Commented Jul 23, 2017 at 14:29
Add a ment  | 

5 Answers 5

Reset to default 3

The problem is that on does not return a promise. Instead, it returns the callback function that was passed as a parameter. on will invoke the callback for the initial data and then again for any changes made to the data.

You most likely want to use once, which does return a promise:

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

Note that the promise's resolved snapshot will contain zero or more children that matched the query. To enumerate the children, you can use the snapshot's forEach method.

I found out the hard way that initializing firebase in a lambda function (e.g. via firebase-admin) will prevent the function from terminating (until the default 6-second timeout) unless you call app.delete() on the firebase app instance. Additionally, you should make sure that every time your run your lambda function you are using a new firebase app instance otherwise you will run into problems.

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

Your Lambda function probably times out after 4 seconds because you set this value when configuring the Lambda function. In order for the your function to wait for the external thing to happen, you can schedule a function to query the value regularly with setTimeout() until the value is there. If that takes longer than 4 seconds, you need to increase the functions timeout, too.

From the AWS Lambda documentation:

Q: How long can an AWS Lambda function execute?

All calls made to AWS Lambda must plete execution within 300 seconds. The default timeout is 3 seconds, but you can set the timeout to any value between 1 and 300 seconds.

I would suggest that you are going to have problems trying to wait for Firebase events from inside a Lambda function. Lambda is designed to be called with data and process data and exit, not to wait for other events to happen. You would be better off using some kind of VPS and running a general Node process to do the database work. Lambda pushing data into Firebase is fine, but what you are trying to achieve with Firebase might be the wrong approach.

You are calling the function before the other function is being called. Try npm sleep() or setTimeout() to give your function a pause.

发布评论

评论列表(0)

  1. 暂无评论