关于实现异步的一些感受
在开发api的时候经常会遇到一些耗时的任务,任务执行的时间往往超过30S还没有返回,这个时候就不适合让接口等待返回,而要放在后台执行。在flask框架中,是借助celery来执行异步操作的,就是把耗时任务放在后台执行,而不让前端等待返回值。
但是放在后台执行往往会遇到以下几个问题:
1. 如何在耗时任务执行完成后,通知前端
有些操作是需要顺序执行的,也就是下一个操作依赖上一个操作的返回值,因此耗时任务在后台执行完后要通知前端拿到返回值去执行下一步操作。
消息队列:当后台的异步任务执行完成之后,通过消息队列给前端发消息,当前端收到特定的消息,例如消息中有特定字段时去执行下一步操作。
前端轮询:使任务有一个状态,前端不断去请求查询任务状态的接口(轮询),当状态是变为完成的时候,去执行下一步操作。
const imageCreateData = await ImageAPI.create(params)
if (imageCreateData.status === 200) {
console.log(imageCreateData.data)
const imageID = imageCreateData.data.id;
const sleep = (delay) => new Promise((resolve) => setTimeout(resolve, delay))
while (1) {
message.success({content: "文件正在上传..."})
await sleep(1000 * 5)
const imageData = await ImageAPI.queryById(imageID)
console.log(imageData)
if (imageData.status === 200 && imageData.data.status === 'active') {
message.success({content: "文件上传成功,开始传输..."})
break;
}
}
request api:在任务结束的时候去request下一步操作的接口
def MyTask(params):
... "任务逻辑"
... "任务逻辑"
... "任务逻辑"
requests.post("http://...") // 请求接口去执行下一步的操作
后端轮询:与前端轮询相似,后端启动一个后台任务,不断去轮询任务完成的状态,
def MyTask(params):
..."任务逻辑"
def GetTaskStatus(taskid):
while(True):
task_status = taskqueryById(taskid)
if task_status == "finish":
break
def do_next(params):
MyTask(params)
GetTaskStatus()
..."下一步逻辑"
2.多节点情况下调用服务不在同一节点的问题
例如三节点的情况,高可用性H.A.(High Availability)HA随机调用,如果一个完整业务逻辑,涉及多个模块,例如导出云主机镜像的逻辑,发起请求后实际的导出逻辑在nova中执行,导出镜像文件在节点1中,而接收接口请求的在节点2中而导致无法保证上传的镜像文件被找到