发送响应后继续执行(Cloudbase for Firebase)

atl*_*teh 11 firebase google-cloud-functions

我正在使用具有https触发器的Firebase函数,我想知道在将响应发送到客户端多长时间后,函数仍在执行.我想向客户端发送响应,然后执行另一个操作(发送邮件).目前我这样做如下:

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

上面的代码对我有用,但是我怀疑代码只能起作用,因为在res.send完成之前发送邮件已经完成了,所以我想知道终止进程是如何工作的以确保代码不会打破.

Kis*_*nga 11

如果预期的响应没有与执行的结果挂钩,那么您可以使用

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

这会在收到请求后立即发回响应,但保持函数运行直到res.end()被调用 您的客户端可以在收到响应后立即结束连接,但云函数将继续在后台运行 不确定这是否有帮助,但考虑到执行发布/订阅需要自己进行一些额外的处理并且需要时间来执行,这可能是一种解决方法,即客户端需要在非常有限的时间内做出响应

  • 这并不总是有效,并且可能经常会失败。一旦响应发送到客户端,云函数就会限制计算资源,并且绝对不能保证任何挂起的异步工作都会完成。 (3认同)
  • 这一假设在实践中并不成立。该函数在发送响应后立即终止。不存在“部分回应”这样的事情。响应会缓冲在内存中并一次性完全发送。您可能有几分之一秒的时间来计算其他内容,但不应依赖于此。我强烈建议您亲自尝试一下,看看它是否真的有效。 (2认同)

Dou*_*son 10

您应该期望HTTP函数在发送响应后终止.任何其他行为都是运气或竞争条件的某种组合.不要编写依赖于运气的代码.

如果您需要在工作完成之前向客户端发送响应,则需要启动第二个功能以继续HTTP功能停止的位置.使用pub/sub函数来执行此操作很常见.让HTTP函数向另一个函数发送发布/订阅消息,然后在发送消息后终止HTTP函数(通过发送响应).

  • 您可以使用 Google Cloud pubsub 客户端发送消息。我自己没做过。https://cloud.google.com/nodejs/docs/reference/pubsub/0.16.x/ (2认同)
  • 这是对 Google 文档的引用,其中明确指出,“..发送 HTTP 响应后执行的代码可能随时被中断” https://cloud.google.com/functions/docs/concepts/exec#function_execution_timeline (2认同)

Ash*_*ton 5

长话短说

虽然 https 函数将在 后不久终止res.send(),但不保证之后的 0 行代码res.send()将被执行。

我认为更完整的答案有两个组成部分:

  1. 正如 Doug 指出的那样,不要放置任何您希望在之后执行的附加代码res.send()
  2. 云函数将在不久后终止res.send(),但不要期望恰好执行 0 行代码

我遇到了一种情况,对于数据库维护脚本,如果没有记录符合我的标准,我就说再见,res.send()并在它之后有额外的逻辑。我预计该片段不会运行,因为我已经终止了请求。

产生意外结果的示例:

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')
})
Run Code Online (Sandbox Code Playgroud)

在上面的示例中,我期望res.send()立即终止该函数 - 事实并非如此,第二个 console.log 也可能会被命中 - 以及您可能拥有的任何其他代码。然而,这并不能得到保证,因此执行可能会在某个时刻突然停止。

产生正确结果的示例:

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')
  }
})
Run Code Online (Sandbox Code Playgroud)

在此版本中,您将看到 1 行 console.logs - 正如我最初的意图。