发送响应后继续执行(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)的主要内容,如果未能解决你的问题,请参考以下文章
Google Cloud Functions - 客户端调用错误(Android Studio):FirebaseFunctionsException:响应不是有效的 JSON 对象
Firebase FCM 使用 Cloud Functions 延迟交付
如何使用 Cloud Functions 接收和解析电子邮件?