Continue execution after sending response (Cloud F

2020-02-01 01:25发布

I'm using Firebase Functions with https triggers, and I was wondering how long after sending the response to the client, the functions keeps executing. I want to send a response to the client and then perform another operation (send a mail). Currently I'm doing this as following:

module.exports.doSomeJob = functions.https.onRequest((req, res) => {
    doSomeAsyncJob()
    .then(() => {
        res.send("Ok");
    })
    .then(() => {
        emailSender.sendEmail();
    })
    .catch(...);
});

The above code is working for me, but I'm suspecting that the code only works because sending the mail has finished before the res.send has completed, so I was wondering how exactly the termination process is working to make sure the code will not break.

3条回答
霸刀☆藐视天下
2楼-- · 2020-02-01 02:03

If the expected response is not pegged to the outcome of the execution, then you can use

module.exports.doSomeJob = functions.https.onRequest((req, res) => {
res.write('SUCCESS')
return doSomeAsyncJob()
.then(() => {
    emailSender.sendEmail();
})
.then(() => {
    res.end();
})
.catch(...);
});

This sends back a response a soon as a request is received, but keeps the function running until res.end() is called Your client can end the connection as soon as a response is received back, but the cloud function will keep running in the background Not sure if this helps, but it might be a workaround where the client needs a response within a very limited time, considering that executing pub/sub requires some extra processing on its own and takes time to execute

查看更多
smile是对你的礼貌
3楼-- · 2020-02-01 02:11

You should expect that the HTTP function terminates the moment after you send the response. Any other behavior is some combination of luck or a race condition. Don't write code that depends on luck.

If you need to send a response to the client before the work is fully complete, you will need to kick off a second function to continue where the HTTP function left off. It's common to use a pub/sub function to do with. Have the HTTP function send a pub/sub message to another function, then terminate the HTTP function (by sending a response) only after the message is sent.

查看更多
家丑人穷心不美
4楼-- · 2020-02-01 02:19

TL;DR

While https functions will terminate shortly after res.send(), it is not guaranteed that 0 lines of code after res.send() will be executed.

I think a fuller answer has 2 components:

  1. as Doug pointed out, do not put any additional code you expect to be executed after res.send()
  2. cloud functions will terminate shortly after res.send(), but don't expect that exactly 0 lines of code will be executed

I ran into a situation where for a db maintenance script, if no records met my criteria, I said goodbye with res.send() and had additional logic after it. I was expecting that piece not to be run, since I've already terminated the request.

Example producing unexpected results:

exports.someFunction = functions.https.onRequest((req, res) => {
  if (exitCriteria === true) {
    // we can exit the function, nothing to do
    console.log('Exit criteria met')
    res.status(200).send()
  }

  // code to handle if someCriteria was falsy
  console.log('Exit criteria not met, continue executing code')
})

In the above example, I was expecting res.send() to terminate the function immediately - this is not so, the second console.log may also be hit - along with any other code you may have. This is not guaranteed, however, so execution may abruptly stop at some point.

Example producing correct results:

exports.someFunction = functions.https.onRequest((req, res) => {
  if (exitCriteria === true) {
    // we can exit the function, nothing to do
    console.log('Exit criteria met')
    res.status(200).send()
  }
  else {
    // code to handle if someCriteria was falsy
    console.log('Exit criteria not met, continue executing code')
  }
})

In this version, you will see exactly 1 line of console.logs - as I was originally intending.

查看更多
登录 后发表回答