提问者:小点点

发送响应后继续执行(Firebase的云函数)


我正在使用带有https触发器的Firebase函数,我想知道在向客户机发送响应之后,函数还会继续执行多久。我想向客户端发送一个响应,然后执行另一个操作(发送邮件)。目前,我正在按如下方式进行此操作:

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

上面的代码对我来说是有效的,但是我怀疑这些代码只是因为在res.send完成之前发送邮件就完成了,所以我想知道终止过程到底是如何工作的,以确保代码不会中断。


共3个答案

匿名用户

您应该期望HTTP函数在发送响应后立即终止。任何其他的行为都是运气或种族条件的某种组合。不要写靠运气的代码。

如果您需要在工作完全完成之前向客户机发送响应,则需要启动第二个函数以继续HTTP函数停止的地方。通常使用pub/sub函数来处理。让HTTP函数向另一个函数发送pub/sub消息,然后仅在消息发送后终止HTTP函数(通过发送响应)。

匿名用户

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

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

这会在收到请求后立即发送响应,但会一直运行函数,直到调用res.end()您的客户机可以在收到响应后立即结束连接,但云函数会一直在后台运行(不确定这是否有帮助),但考虑到执行pub/sub本身需要一些额外的处理并需要时间,因此它可能是客户机在非常有限的时间内需要响应的一种解决方法

匿名用户

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

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

我遇到过这样一种情况:对于一个db维护脚本,如果没有记录满足我的标准,我就用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')
})

在上面的示例中,我期望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')
  }
})

在这个版本中,您将看到只有一行console.logs-正如我最初所希望的那样。