gocron/internal/routers/task/task.go

294 lines
8.0 KiB
Go

package task
import (
"strconv"
"strings"
"github.com/go-macaron/binding"
"github.com/jakecoffman/cron"
"github.com/ouqiang/gocron/internal/models"
"github.com/ouqiang/gocron/internal/modules/logger"
"github.com/ouqiang/gocron/internal/modules/utils"
"github.com/ouqiang/gocron/internal/routers/base"
"github.com/ouqiang/gocron/internal/service"
"gopkg.in/macaron.v1"
)
type TaskForm struct {
Id int
Level models.TaskLevel `binding:"Required;In(1,2)"`
DependencyStatus models.TaskDependencyStatus
DependencyTaskId string
Name string `binding:"Required;MaxSize(32)"`
Spec string
Protocol models.TaskProtocol `binding:"In(1,2)"`
Command string `binding:"Required;MaxSize(256)"`
HttpMethod models.TaskHTTPMethod `binding:"In(1,2)"`
Timeout int `binding:"Range(0,86400)"`
Multi int8 `binding:"In(1,2)"`
RetryTimes int8
RetryInterval int16
HostId string
Tag string
Remark string
NotifyStatus int8 `binding:"In(1,2,3,4)"`
NotifyType int8 `binding:"In(1,2,3,4)"`
NotifyReceiverId string
NotifyKeyword string
}
func (f TaskForm) Error(ctx *macaron.Context, errs binding.Errors) {
if len(errs) == 0 {
return
}
json := utils.JsonResponse{}
content := json.CommonFailure("表单验证失败, 请检测输入")
ctx.Resp.Write([]byte(content))
}
// 首页
func Index(ctx *macaron.Context) string {
taskModel := new(models.Task)
queryParams := parseQueryParams(ctx)
total, err := taskModel.Total(queryParams)
if err != nil {
logger.Error(err)
}
tasks, err := taskModel.List(queryParams)
if err != nil {
logger.Error(err)
}
for i, item := range tasks {
tasks[i].NextRunTime = service.ServiceTask.NextRunTime(item)
}
jsonResp := utils.JsonResponse{}
return jsonResp.Success(utils.SuccessContent, map[string]interface{}{
"total": total,
"data": tasks,
})
}
// Detail 任务详情
func Detail(ctx *macaron.Context) string {
id := ctx.ParamsInt(":id")
taskModel := new(models.Task)
task, err := taskModel.Detail(id)
jsonResp := utils.JsonResponse{}
if err != nil || task.Id == 0 {
logger.Errorf("编辑任务#获取任务详情失败#任务ID-%d", id)
return jsonResp.Success(utils.SuccessContent, nil)
}
return jsonResp.Success(utils.SuccessContent, task)
}
// 保存任务 todo 拆分为多个方法
func Store(ctx *macaron.Context, form TaskForm) string {
json := utils.JsonResponse{}
taskModel := models.Task{}
var id = form.Id
nameExists, err := taskModel.NameExist(form.Name, form.Id)
if err != nil {
return json.CommonFailure(utils.FailureContent, err)
}
if nameExists {
return json.CommonFailure("任务名称已存在")
}
if form.Protocol == models.TaskRPC && form.HostId == "" {
return json.CommonFailure("请选择主机名")
}
taskModel.Name = form.Name
taskModel.Protocol = form.Protocol
taskModel.Command = strings.TrimSpace(form.Command)
taskModel.Timeout = form.Timeout
taskModel.Tag = form.Tag
taskModel.Remark = form.Remark
taskModel.Multi = form.Multi
taskModel.RetryTimes = form.RetryTimes
taskModel.RetryInterval = form.RetryInterval
if taskModel.Multi != 1 {
taskModel.Multi = 0
}
taskModel.NotifyStatus = form.NotifyStatus - 1
taskModel.NotifyType = form.NotifyType - 1
taskModel.NotifyReceiverId = form.NotifyReceiverId
taskModel.NotifyKeyword = form.NotifyKeyword
taskModel.Spec = form.Spec
taskModel.Level = form.Level
taskModel.DependencyStatus = form.DependencyStatus
taskModel.DependencyTaskId = strings.TrimSpace(form.DependencyTaskId)
if taskModel.NotifyStatus > 0 && taskModel.NotifyType != 3 && taskModel.NotifyReceiverId == "" {
return json.CommonFailure("至少选择一个通知接收者")
}
taskModel.HttpMethod = form.HttpMethod
if taskModel.Protocol == models.TaskHTTP {
command := strings.ToLower(taskModel.Command)
if !strings.HasPrefix(command, "http://") && !strings.HasPrefix(command, "https://") {
return json.CommonFailure("请输入正确的URL地址")
}
if taskModel.Timeout > 300 {
return json.CommonFailure("HTTP任务超时时间不能超过300秒")
}
}
if taskModel.RetryTimes > 10 || taskModel.RetryTimes < 0 {
return json.CommonFailure("任务重试次数取值0-10")
}
if taskModel.RetryInterval > 3600 || taskModel.RetryInterval < 0 {
return json.CommonFailure("任务重试间隔时间取值0-3600")
}
if taskModel.DependencyStatus != models.TaskDependencyStatusStrong &&
taskModel.DependencyStatus != models.TaskDependencyStatusWeak {
return json.CommonFailure("请选择依赖关系")
}
if taskModel.Level == models.TaskLevelParent {
_, err = cron.Parse(form.Spec)
if err != nil {
return json.CommonFailure("crontab表达式解析失败", err)
}
} else {
taskModel.DependencyTaskId = ""
taskModel.Spec = ""
}
if id > 0 && taskModel.DependencyTaskId != "" {
dependencyTaskIds := strings.Split(taskModel.DependencyTaskId, ",")
if utils.InStringSlice(dependencyTaskIds, strconv.Itoa(id)) {
return json.CommonFailure("不允许设置当前任务为子任务")
}
}
if id == 0 {
// 任务添加后开始调度执行
taskModel.Status = models.Running
id, err = taskModel.Create()
} else {
_, err = taskModel.UpdateBean(id)
}
if err != nil {
return json.CommonFailure("保存失败", err)
}
taskHostModel := new(models.TaskHost)
if form.Protocol == models.TaskRPC {
hostIdStrList := strings.Split(form.HostId, ",")
hostIds := make([]int, len(hostIdStrList))
for i, hostIdStr := range hostIdStrList {
hostIds[i], _ = strconv.Atoi(hostIdStr)
}
taskHostModel.Add(id, hostIds)
} else {
taskHostModel.Remove(id)
}
status, _ := taskModel.GetStatus(id)
if status == models.Enabled && taskModel.Level == models.TaskLevelParent {
addTaskToTimer(id)
}
return json.Success("保存成功", nil)
}
// 删除任务
func Remove(ctx *macaron.Context) string {
id := ctx.ParamsInt(":id")
json := utils.JsonResponse{}
taskModel := new(models.Task)
_, err := taskModel.Delete(id)
if err != nil {
return json.CommonFailure(utils.FailureContent, err)
}
taskHostModel := new(models.TaskHost)
taskHostModel.Remove(id)
service.ServiceTask.Remove(id)
return json.Success(utils.SuccessContent, nil)
}
// 激活任务
func Enable(ctx *macaron.Context) string {
return changeStatus(ctx, models.Enabled)
}
// 暂停任务
func Disable(ctx *macaron.Context) string {
return changeStatus(ctx, models.Disabled)
}
// 手动运行任务
func Run(ctx *macaron.Context) string {
id := ctx.ParamsInt(":id")
json := utils.JsonResponse{}
taskModel := new(models.Task)
task, err := taskModel.Detail(id)
if err != nil || task.Id <= 0 {
return json.CommonFailure("获取任务详情失败", err)
}
task.Spec = "手动运行"
service.ServiceTask.Run(task)
return json.Success("任务已开始运行, 请到任务日志中查看结果", nil)
}
// 改变任务状态
func changeStatus(ctx *macaron.Context, status models.Status) string {
id := ctx.ParamsInt(":id")
json := utils.JsonResponse{}
taskModel := new(models.Task)
_, err := taskModel.Update(id, models.CommonMap{
"Status": status,
})
if err != nil {
return json.CommonFailure(utils.FailureContent, err)
}
if status == models.Enabled {
addTaskToTimer(id)
} else {
service.ServiceTask.Remove(id)
}
return json.Success(utils.SuccessContent, nil)
}
// 添加任务到定时器
func addTaskToTimer(id int) {
taskModel := new(models.Task)
task, err := taskModel.Detail(id)
if err != nil {
logger.Error(err)
return
}
service.ServiceTask.RemoveAndAdd(task)
}
// 解析查询参数
func parseQueryParams(ctx *macaron.Context) models.CommonMap {
var params models.CommonMap = models.CommonMap{}
params["Id"] = ctx.QueryInt("id")
params["HostId"] = ctx.QueryInt("host_id")
params["Name"] = ctx.QueryTrim("name")
params["Protocol"] = ctx.QueryInt("protocol")
params["Tag"] = ctx.QueryTrim("tag")
status := ctx.QueryInt("status")
if status >= 0 {
status -= 1
}
params["Status"] = status
base.ParsePageAndPageSize(ctx, params)
return params
}