diff --git a/.gitignore b/.gitignore index 20276f6..d36df92 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,4 @@ conf/app.ini conf/ansible_hosts.ini profile/* public/resource/javascript/vue.js +gocron diff --git a/routers/task/task.go b/routers/task/task.go index 9b7de17..c0d9f03 100644 --- a/routers/task/task.go +++ b/routers/task/task.go @@ -7,6 +7,7 @@ import ( "github.com/ouqiang/gocron/modules/utils" "github.com/ouqiang/gocron/service" "strconv" + "github.com/jakecoffman/cron" ) func Index(ctx *macaron.Context) { @@ -48,6 +49,10 @@ type TaskForm struct { func Store(ctx *macaron.Context, form TaskForm) string { json := utils.JsonResponse{} taskModel := models.Task{} + _, err := cron.Parse(form.Spec) + if err != nil { + return json.CommonFailure("crontab表达式解析失败", err) + } nameExists, err := taskModel.NameExist(form.Name) if err != nil { return json.CommonFailure(utils.FailureContent, err) diff --git a/service/task.go b/service/task.go index 5ebd80a..4687cef 100644 --- a/service/task.go +++ b/service/task.go @@ -38,13 +38,14 @@ func (task *Task) Initialize() { func (task *Task) Add(taskModel models.TaskHost) { taskFunc := createHandlerJob(taskModel) if taskFunc == nil { - logger.Error("添加任务#不存在的任务协议编号", taskModel.Protocol) + logger.Error("创建任务处理Job失败,不支持的任务协议#", taskModel.Protocol) return } cronName := strconv.Itoa(taskModel.Id) Cron.RemoveJob(cronName) - Cron.AddFunc(taskModel.Spec, taskFunc, cronName) + err := Cron.AddFunc(taskModel.Spec, taskFunc, cronName) + logger.Error("添加任务到调度器失败#", err) } type Handler interface { @@ -61,7 +62,7 @@ func (h *HTTPHandler) Run(taskModel models.TaskHost) (result string, err error) } req, err := http.NewRequest("POST", taskModel.Command, nil) if err != nil { - logger.Error("创建HTTP请求错误-", err.Error()) + logger.Error("任务处理#创建HTTP请求错误-", err.Error()) return } req.Header.Set("Content-type", "application/x-www-form-urlencoded") @@ -74,12 +75,12 @@ func (h *HTTPHandler) Run(taskModel models.TaskHost) (result string, err error) } }() if err != nil { - logger.Error("HTTP请求错误-", err.Error()) + logger.Error("任务处理HTTP请求错误-", err.Error()) return } body, err := ioutil.ReadAll(resp.Body) if err != nil { - logger.Error("读取HTTP请求返回值失败-", err.Error()) + logger.Error("任务处理#读取HTTP请求返回值失败-", err.Error()) } return string(body), err @@ -145,7 +146,7 @@ func createHandlerJob(taskModel models.TaskHost) cron.FuncJob { taskFunc := func() { taskLogId, err := createTaskLog(taskModel) if err != nil { - logger.Error("写入任务日志失败-", err) + logger.Error("任务开始执行#写入任务日志失败-", err) return } // err != nil 执行失败, 失败重试3次 @@ -156,12 +157,12 @@ func createHandlerJob(taskModel models.TaskHost) cron.FuncJob { if err == nil { break } else { - logger.Error("执行失败#tasklog.id-" + strconv.FormatInt(taskLogId, 10) + "#尝试次数-" + strconv.Itoa(i + 1) + "#" + err.Error() + " " + result) + logger.Error("任务执行失败#tasklog.id-" + strconv.FormatInt(taskLogId, 10) + "#尝试次数-" + strconv.Itoa(i + 1) + "#" + err.Error() + " " + result) } } _, err = updateTaskLog(taskLogId, result, err) if err != nil { - logger.Error("更新任务日志失败-", err) + logger.Error("任务结束#更新任务日志失败-", err) } } diff --git a/vendor/github.com/jakecoffman/cron/cron.go b/vendor/github.com/jakecoffman/cron/cron.go index 9e3f378..3b4af82 100644 --- a/vendor/github.com/jakecoffman/cron/cron.go +++ b/vendor/github.com/jakecoffman/cron/cron.go @@ -90,13 +90,18 @@ type FuncJob func() func (f FuncJob) Run() { f() } // AddFunc adds a func to the Cron to be run on the given schedule. -func (c *Cron) AddFunc(spec string, cmd func(), name string) { - c.AddJob(spec, FuncJob(cmd), name) +func (c *Cron) AddFunc(spec string, cmd func(), name string) error { + return c.AddJob(spec, FuncJob(cmd), name) } // AddFunc adds a Job to the Cron to be run on the given schedule. -func (c *Cron) AddJob(spec string, cmd Job, name string) { - c.Schedule(Parse(spec), cmd, name) +func (c *Cron) AddJob(spec string, cmd Job, name string) error { + schedule, err := Parse(spec) + if err != nil { + return err + } + c.Schedule(schedule, cmd, name) + return nil } // RemoveJob removes a Job from the Cron based on name. diff --git a/vendor/github.com/jakecoffman/cron/parser.go b/vendor/github.com/jakecoffman/cron/parser.go index 7d0ee9d..28326c5 100644 --- a/vendor/github.com/jakecoffman/cron/parser.go +++ b/vendor/github.com/jakecoffman/cron/parser.go @@ -6,6 +6,7 @@ import ( "strconv" "strings" "time" + "fmt" ) // Parse returns a new crontab schedule representing the given spec. @@ -14,7 +15,10 @@ import ( // It accepts // - Full crontab specs, e.g. "* * * * * ?" // - Descriptors, e.g. "@midnight", "@every 1h30m" -func Parse(spec string) Schedule { +func Parse(spec string) (Schedule, error) { + if len(spec) == 0 { + return nil, fmt.Errorf("Empty spec string") + } if spec[0] == '@' { return parseDescriptor(spec) } @@ -23,7 +27,7 @@ func Parse(spec string) Schedule { // (second) (minute) (hour) (day of month) (month) (day of week, optional) fields := strings.Fields(spec) if len(fields) != 5 && len(fields) != 6 { - log.Panicf("Expected 5 or 6 fields, found %d: %s", len(fields), spec) + return nil, fmt.Errorf("Expected 5 or 6 fields, found %d: %s", len(fields), spec) } // If a sixth field is not provided (DayOfWeek), then it is equivalent to star. @@ -40,7 +44,7 @@ func Parse(spec string) Schedule { Dow: getField(fields[5], dow), } - return schedule + return schedule, nil } // getField returns an Int with the bits set representing all of the times that @@ -156,7 +160,7 @@ func all(r bounds) uint64 { // parseDescriptor returns a pre-defined schedule for the expression, or panics // if none matches. -func parseDescriptor(spec string) Schedule { +func parseDescriptor(spec string) (Schedule,error) { switch spec { case "@yearly", "@annually": return &SpecSchedule{ @@ -166,7 +170,7 @@ func parseDescriptor(spec string) Schedule { Dom: 1 << dom.min, Month: 1 << months.min, Dow: all(dow), - } + }, nil case "@monthly": return &SpecSchedule{ @@ -176,7 +180,7 @@ func parseDescriptor(spec string) Schedule { Dom: 1 << dom.min, Month: all(months), Dow: all(dow), - } + }, nil case "@weekly": return &SpecSchedule{ @@ -186,7 +190,7 @@ func parseDescriptor(spec string) Schedule { Dom: all(dom), Month: all(months), Dow: 1 << dow.min, - } + }, nil case "@daily", "@midnight": return &SpecSchedule{ @@ -196,7 +200,7 @@ func parseDescriptor(spec string) Schedule { Dom: all(dom), Month: all(months), Dow: all(dow), - } + }, nil case "@hourly": return &SpecSchedule{ @@ -206,18 +210,17 @@ func parseDescriptor(spec string) Schedule { Dom: all(dom), Month: all(months), Dow: all(dow), - } + }, nil } const every = "@every " if strings.HasPrefix(spec, every) { duration, err := time.ParseDuration(spec[len(every):]) if err != nil { - log.Panicf("Failed to parse duration %s: %s", spec, err) - } - return Every(duration) + return nil, fmt.Errorf("Failed to parse duration %s: %s", spec, err) + } + return Every(duration),nil } - log.Panicf("Unrecognized descriptor: %s", spec) - return nil + return nil, fmt.Errorf("Unrecognized descriptor: %s", spec) }