1. 异步任务的实现

异步任务是为了在做一些运行过长的操作时,能够将任务转至后台,同时返回响应,在前端告知用户已在执行任务,用户不用等待任务的同步完成,可以在异步任务进行的同时进行一些其他的浏览或操作。

异步任务的实现是利用一个切片,在程序初始化时,启动一个协程来循环扫描这个切片。当切片中加入一个或多个任务时,会取出一个任务执行。并且会有辨别码,辨别任务是否是执行中/执行完毕/执行失败。

if len(manager.TaskSlice) == 0 {
    continue
}
key := manager.PopSlice()
task, ok := manager.Tasks[key]
if !ok {
    // 如果没有该任务,则不往下执行
    continue
}
if task.Status == types.TaskFailed {
    // 如果任务执行失败,则重新放进任务里,等待重新执行
    manager.PushSlice(key)
    continue
}
// 设置任务为正在执行
manager.Tasks[key].Status = types.TaskOnGoing
if err := task.DetailInterface.ExecTask(); err != nil {
    config.Logger.Errorf("%s 的错误为 %v", key, err)
    // 设置任务为失败, 重新放入任务队列
    manager.Tasks[key].Status = types.TaskFailed
    manager.PushSlice(key)
} else {
    // 任务执行成功
    config.Logger.Infof("%s执行完毕", key)
    delete(manager.Tasks, key)
}

1.1 异步任务的添加

将任务的信息写入map,再将该map写入到任务切片中等待执行:

func (manager *Manager) Add(topic string, sign string, detailInterface DetailInterface)  {
    ……
    key := fmt.Sprintf("%s_%s", topic, sign)
    manager.Tasks[key] = &Detail{
        Topic:  topic,
        Sign: sign,
        DetailInterface: detailInterface,
        Status: types.TaskOnGoing,
    }
    manager.TaskSlice = append(manager.TaskSlice, key)
}

1.2 异步任务的删除

异步任务删除需要根据key从切片中获取其状态,判断该状态是否可以在切片删除:

taskInfo, exist := task.GetTaskManager().GetTaskInfoByKey(req.Id)
if taskInfo.Status == types.TaskOnGoing {
    err = errors.Wrap(err, status.TaskStatusErr)
    return
}
task.GetTaskManager().DelByKey(req.Id)

func (manager *Manager) DelByKey(key string) {
    delete(manager.Tasks, key)
}

1.3 异步任务的重新开始

异步任务重新开始需要根据key从切片中获取状态,判断状态是否可以重新加入切片中

taskInfo, exist := task.GetTaskManager().GetTaskInfoByKey(req.Id)
if taskInfo.Status == types.TaskOnGoing {
    err = errors.Wrap(err, status.TaskStatusErr)
    return
}
task.GetTaskManager().RestartByKey(req.Id)

func (manager *Manager) RestartByKey(key string) {
    manager.Tasks[key].Status = types.TaskOnGoing
}