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

Posted

技术标签:

【中文标题】发送响应后继续执行(Cloud Functions for Firebase)【英文标题】:Continue execution after sending response (Cloud Functions for Firebase) 【发布时间】:2018-09-19 16:20:06 【问题描述】:

我正在使用带有 https 触发器的 Firebase 函数,我想知道在向客户端发送响应后多久,函数会继续执行。我想向客户端发送响应,然后执行另一个操作(发送邮件)。 目前我正在这样做:

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

上面的代码对我有用,但我怀疑代码只是因为在 res.send 完成之前发送邮件已经完成,所以我想知道终止过程究竟是如何工作以确保代码不会中断。

【问题讨论】:

【参考方案1】:

TL;DR

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

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

    正如Doug 所指出的,不要在res.send() 之后添加您希望执行的任何附加代码 云函数将在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')
)

在上面的例子中,我期待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')
  
)

在这个版本中,您将看到 1 行 console.logs - 正如我原本打算的那样。

【讨论】:

你知道我们是否可以不使用else 而只使用return res.send()【参考方案2】:

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

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

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

【讨论】:

这太完美了,谢谢!!我的用例是 Slack,如果它在 300 毫秒内没有收到200 状态响应,则会出错。这似乎解决了我遇到的问题。 我很高兴它有帮助 客户端/调用者的连接是否保持活动状态? 这并不总是有效,并且可能会经常失败。 Cloud Functions 会在将响应发送到客户端后立即限制计算资源,并且绝对不能保证任何待处理的异步工作都会完成。 这种假设在实践中并不成立。该函数在响应发送后立即终止。没有所谓的“部分回应”。响应缓存在内存中,并一次性发送。你可能有几分之一秒的时间来计算其他东西,但这不应该依赖。我强烈建议您自己尝试一下,看看它是否真的有效。【参考方案3】:

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

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

【讨论】:

Hé 这似乎是唯一的方法。但是,如果我查看 pub/sub 的文档,我似乎只找到了订阅方,而不是如何从云函数中调用它。您能否扩展您的答案以包括如何实际执行此操作? 您可以使用谷歌云发布订阅客户端发送消息。我自己没有做过。 cloud.google.com/nodejs/docs/reference/pubsub/0.16.x 这是对 Google 文档的引用,其中明确说明了这一点,“..发送 HTTP 响应后执行的代码可能随时中断”cloud.google.com/functions/docs/concepts/… @Unnikrishnan 这里有一个很好的例子:***.com/a/61525321/867631 此解决方案的问题是发布/订阅可能需要 2 分钟才能触发 - 在生产中看到这一点。

以上是关于发送响应后继续执行(Cloud Functions for Firebase)的主要内容,如果未能解决你的问题,请参考以下文章

发送 HTTP 响应后继续 PHP 执行

Google Cloud Functions - 客户端调用错误(Android Studio):FirebaseFunctionsException:响应不是有效的 JSON 对象

Firebase FCM 使用 Cloud Functions 延迟交付

如何使用 Cloud Functions 接收和解析电子邮件?

从 Cloud Code 向 iOS 设备发送有关进度的更新(解析)

Cloud Functions Cors 错误“对预检请求的响应未通过访问控制检查”