腾讯云云开发云函数 之 异步执行,提前返回

云函数的特性是,当 main 函数 return 时,执行进程会被立即冻结。这一点在官方文档Node.js 8 的异步行为中有提到。

对于异步函数,主流程执行完成后,函数实例进程会被冻结,进程中的所有异步任务会暂停执行,直到这个进程被再次唤起。
另一方面,如果函数实例进程由于某些原因没被复用(例如更新了函数代码),这个异步流程中的代码就永远不会被执行

但是有些场景下,云函数需要很长的执行时间,例如,Twikoo 通过 Akismet 检测垃圾评论的过程。按照特性,在检测过程结束前,就不能异步检测,提前返回结果给前端,否则检测进程就会被冻结,导致检测失败。我们只能 await 同步检测,造成请求响应慢,用户体验差。

按照 Java 的习惯,我们会启动新的线程执行长时间的任务,在云函数中怎样实现?

首先 node.js 想要实现多线程是不可能的,那我们换个思路,可以实现多进程吗?可以通过 “云函数调用云函数” 实现多个云函数进程并发执行吗?可以。

index.js
1
2
3
4
5
6
7
8
9
10
11
12
try {
const isSpam = await app.callFunction({
name: 'twikoo', // 调起另一个云函数进程
data: {
event: 'CHECK_SPAM', // 检查垃圾评论
comment // 传入检查的评论数据
}
}, { timeout: 300 }) // 设置较短的 timeout 来实现异步
return isSpam.result.isSpam // 如果没有超时,可以直接拿到返回结果
} catch (e) {
console.log('开始异步检测垃圾评论') // 如果超时了,两个云函数进程也都会正常执行下去
}

callFunction 提供了请求超时时间的设置,即使请求超时,被调用的云函数也是会继续执行完的。那我们就利用这一点,设置较短的 timeout 来实现异步。这样,用户调起的云函数就能够迅速返回结果,垃圾评论检测就可以在另一个进程中慢慢执行了。

肯定有人会问,想要保护起来这种“异步云函数”,只能内部调用,不能外部调用,该怎么实现?这里也提供一个简单的方法。

index.js
1
2
3
4
5
6
7
8
9
10
11
exports.main = async (event, context) => {
if (!isRecursion(context)) {
return // 被外部调用,直接返回
}
}

// 判断是否为外部调用(即云函数调用云函数)
function isRecursion (context) {
const envObj = tcb.getCloudbaseContext(context)
return envObj.TCB_SOURCE.substr(-3, 3) === 'scf'
}

相关完整代码请查看 Twikoo 源码

腾讯云云开发云函数 之 异步执行,提前返回

https://www.imaegoo.com/2020/tcb-functions-async/

作者

iMaeGoo

发布于

2020-12-24

更新于

2020-12-24

许可协议

CC BY 4.0

评论