4

Should HTTPS functions return asynchronous promises like realtime functions have to? We haven't been returning in HTTPS functions (just using res.status.send etc), and it looks like firebase/function-samples aren't either. But the documentation is slightly ambiguous https://firebase.google.com/docs/functions/terminate-functions .

KENdi
  • 7,576
  • 2
  • 16
  • 31
Alan
  • 1,510
  • 1
  • 18
  • 35

4 Answers4

13

This works now in the latest Firebase:

exports.asyncFunction = functions.https.onRequest(async (request, response) => {
    const result = await someAsyncFunction();
    response.send(result);
});
David Veszelovszki
  • 2,574
  • 1
  • 24
  • 23
8

HTTP functions currently do not respect returned promises - they require a sent result in order to terminate normally. If an HTTP function doesn't send a result, it will time out.

All other types of functions require a returned promise in order to wait for asynchronous work to fully complete.

If you don't have any async work to wait for, you can just return immediately.

These are the three cases outlined in the docs.

Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441
  • Thanks @Doug Stevenson We are sending res results, but we weren't sure if a HTTP function stayed alive if it has non-returned asynchronous code. For the docs I'm reading here, it reads as if HTTP functions require returning asynch AND sending res results: https://firebase.google.com/docs/functions/terminate-functions – Alan Aug 09 '17 at 12:43
  • 2
    HTTP triggers just require a response sent. If you need to use promises to coordinate your work, then do so, but returning a promise from the function won't do anything. You must send a response in every possible termination point in your code. – Doug Stevenson Aug 10 '17 at 01:13
  • @DougStevenson does the function terminate on return? what if i want to return immediately to user but continue running the function to completion (eg Stripe call that takes 5s which the user doesn’t really have to wait for) – Fakeer Jun 23 '20 at 15:18
  • @Fakeer https://stackoverflow.com/questions/49746980/continue-execution-after-sending-response-cloud-functions-for-firebase – Doug Stevenson Jun 23 '20 at 15:20
3

After much looking around , this is implementation with a Promise worked for me to return a value from a Google Cloud Function where the function needs to make a third-party asynchronous call :

exports.getSomeAccessToken = functions.https.onCall((data, context) => {

    var dataStr = JSON.stringify(data, null, '\t');   
    console.log('ENTER [getSomeAccessToken], got dataStr:  ' + dataStr);

    return new Promise((resolve, reject) => {

        gateway.clientToken.generate({}, function (err, gatewayResponse) {

            var result = {
                clientToken: gatewayResponse.clientToken
            };

            var resultStr = JSON.stringify(result, null, '\t');
            console.log("resultStr : " + resultStr);

            resolve(result);
        });
    });

});
Gene Bo
  • 11,284
  • 8
  • 90
  • 137
1

Your cloud functions should return"end" with either of the following

res.redirect(), res.send(), or res.end()

What they mean by returning promises, is lets imagine you have a cloud function that updated a node in your realtime database, you would like to complete that work before responding to the HTTP request.

Example code

let RemoveSomething = functions.https.onRequest((req, res) => {
    cors(req, res, () => {
        // Remove something
        DoDatabaseWork()
            .then(function (result) {
                res.status(200).send();
            })
            .catch(function (err) {
                console.error(err);
                res.status(501).send();
            });
    });
});

Update: Added DoDatabaseWork example.

const DoDatabaseWork = function () {
    return new Promise(function (resolve, reject) {
        // Remove SomeNode
        admin.database().ref('/someNode/').remove()
            .then(function (result) {
                resolve();
            })
            .catch(function (err) {
                console.error(err);
                reject();
            });
    });
}
Kim
  • 1,158
  • 8
  • 18
  • Your second example doesn't show what kind of function it is, but it's not appropriate for HTTP functions. HTTP functions don't currently observe any returned promises. They only use the sent result as an indicator when the function is complete. – Doug Stevenson Aug 09 '17 at 12:17
  • The first code piece is the HTTP function, it calls DoDatabaseWork "2nd example" and waits for it to complete the database work "remove a node", then the HTTP function returns with either statuscode 200 or 501. – Kim Aug 09 '17 at 12:21
  • 1
    You can just return the promise from remove() in that case. There's no need to create a new promise just for that. – Doug Stevenson Aug 09 '17 at 12:31
  • Allright, I'm still in the process of getting my head around Promises – Kim Aug 09 '17 at 12:35