How do I exit a lambda function that has a call to Firebase storage?

220 Views Asked by At

I'm trying to implement an Alexa skill (written with Jovo) that accesses audio files that we have stored in Google's Firebase storage. However, I cannot get the lambda function to return, no matter what timeout value that I give. I believe my problem is in how I am handling async code within Lambda, but I can't figure out the correct syntax for what I am trying to do, especially within the Jovo framework.

Here's a version of some code which has the issue. In the real code it passes the url to an audio player, but this example is much simpler to demonstrate the problem:

app.setHandler({
  async LAUNCH() {
    firebase.initializeApp(firebaseConfig);
    const storageFiles = firebase.storage().ref().child('EN');
    const storageFile = storageFiles.child('1.mp3');
    const url = await storageFile.getDownloadURL();
    console.log(`My URL: ${url}`);
    this.tell(`Ok, done with getting the URL`);
  },
... More Jovo intent calls ...
});
module.exports.app = app;

When I run this in a Lambda function, I see the console.log with a good URL printed out. I also see the SSML string constructed, but I never hear the phrase and the Lambda function times out (even with a 20 sec timeout). If I comment out the getDownloadURL line, the function returns just fine. Also, if I run this outside of Lambda with jovo run, it works ok there as well.

Bottom line: what do I need to do to be able to use the getDownloadURL() method within a lambda function?

2

There are 2 best solutions below

0
On

I have found a solution to my issue. The Jovo framework creates a Lambda handler function that looks like this (in index.js):

// AWS Lambda
exports.handler = async (event, context, callback) => {
    await app.handle(new Lambda(event, context, callback));
};

I needed to change the default Lambda behavior by setting the callbackWaitForEmptyEventLoop to false. The handler function now looks like:

// AWS Lambda
exports.handler = async (event, context, callback) => {
    context.callbackWaitsForEmptyEventLoop = false;
    await app.handle(new Lambda(event, context, callback));
};

Once I made this change I was able to successfully get URLs from Firebase storage and play them on the Alexa audio player via a Lambda function. The default Lambda behavior is to leave certain connections open (I believe for serverless perfomance reasons), and this change modifies that behavior.

1
On

As console.log is shown properly the getDownloadURL() is working fine. Async fiction should return promise. I think you are missing something like return url. Please check this question for async usage: here