diff --git a/README.md b/README.md index 6d5e26e..ebadcf6 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ ## 安装, 解压后执行 ```shell - Windows ./gocron.exe web + Windows gocron.exe web Linux、OSX ./gocron web ``` 可选参数 diff --git a/models/model.go b/models/model.go index e1d2be1..70a7862 100644 --- a/models/model.go +++ b/models/model.go @@ -21,6 +21,7 @@ const ( Enabled Status = 1 // 启用 Running Status = 1 // 运行中 Finish Status = 2 // 完成 + Cancel Status = 3 // 取消 ) const ( diff --git a/models/task.go b/models/task.go index ef86378..75649dd 100644 --- a/models/task.go +++ b/models/task.go @@ -22,6 +22,7 @@ type Task struct { Protocol TaskProtocol `xorm:"tinyint notnull"` // 协议 1:http 2:ssh-command 3: 系统命令 Command string `xorm:"varchar(256) notnull"` // URL地址或shell命令 Timeout int `xorm:"mediumint notnull default 0"` // 任务执行超时时间(单位秒),0不限制 + Multi int8 `xorm:"tinyint notnull default 1"` // 是否允许多实例运行 RetryTimes int8 `xorm:"tinyint notnull default 0"` // 重试次数 HostId int16 `xorm:"smallint notnull default 0"` // SSH host id, Remark string `xorm:"varchar(100) notnull default ''"` // 备注 @@ -57,7 +58,7 @@ func (task *Task) Create() (insertId int, err error) { } func (task *Task) UpdateBean(id int) (int64, error) { - return Db.ID(id).UseBool("status").Update(task) + return Db.ID(id).UseBool("status,multi").Update(task) } // 更新 diff --git a/models/task_log.go b/models/task_log.go index 5200254..8371e16 100644 --- a/models/task_log.go +++ b/models/task_log.go @@ -21,15 +21,13 @@ type TaskLog struct { Hostname string `xorm:"varchar(128) notnull defalut '' "` // SSH主机名,逗号分隔 StartTime time.Time `xorm:"datetime created"` // 开始执行时间 EndTime time.Time `xorm:"datetime updated"` // 执行完成(失败)时间 - Status Status `xorm:"tinyint notnull default 1"` // 状态 0:执行失败 1:执行中 2:执行完毕 + Status Status `xorm:"tinyint notnull default 1"` // 状态 0:执行失败 1:执行中 2:执行完毕 3:任务取消(上次任务未执行完成) Result string `xorm:"text notnull defalut '' "` // 执行结果 TotalTime int `xorm:"-"` // 执行总时长 BaseModel `xorm:"-"` } func (taskLog *TaskLog) Create() (insertId int64, err error) { - taskLog.Status = Running - _, err = Db.Insert(taskLog) if err == nil { insertId = taskLog.Id diff --git a/modules/app/app.go b/modules/app/app.go index f4fd975..a18cb23 100644 --- a/modules/app/app.go +++ b/modules/app/app.go @@ -14,6 +14,7 @@ var ( AppDir string // 应用根目录 ConfDir string // 配置目录 LogDir string // 日志目录 + DataDir string // 存放session等 AppConfig string // 应用配置文件 Installed bool // 应用是否安装过 ) @@ -28,8 +29,9 @@ func InitEnv() { AppDir = wd ConfDir = AppDir + "/conf" LogDir = AppDir + "/log" + DataDir = AppDir + "/data" AppConfig = ConfDir + "/app.ini" - checkDirExists(ConfDir, LogDir) + checkDirExists(ConfDir, LogDir, DataDir) Installed = IsInstalled() if Installed { InitDb() diff --git a/routers/routers.go b/routers/routers.go index 691590e..efe33b2 100644 --- a/routers/routers.go +++ b/routers/routers.go @@ -105,7 +105,10 @@ func RegisterMiddleware(m *macaron.Macaron) { // 渲染具有缩进格式的 XML,默认为不缩进 IndentXML: true, })) - m.Use(session.Sessioner()) + m.Use(session.Sessioner(session.Options{ + Provider: "file", + ProviderConfig: app.DataDir + "/sessions", + })) m.Use(csrf.Csrfer()) m.Use(toolbox.Toolboxer(m)) checkAppInstall(m) diff --git a/routers/task/task.go b/routers/task/task.go index b943a4d..a9420b4 100644 --- a/routers/task/task.go +++ b/routers/task/task.go @@ -20,6 +20,7 @@ type TaskForm struct { Protocol models.TaskProtocol `binding:"In(1,2,3)"` Command string `binding:"Required;MaxSize(512)"` Timeout int `binding:"Range(0,86400)"` + Multi int8 `binding:"In(1,2)"` RetryTimes int8 HostId int16 Remark string @@ -119,10 +120,14 @@ func Store(ctx *macaron.Context, form TaskForm) string { taskModel.Timeout = form.Timeout taskModel.Remark = form.Remark taskModel.Status = form.Status + taskModel.Multi = form.Multi taskModel.RetryTimes = form.RetryTimes if taskModel.Status != models.Enabled { taskModel.Status = models.Disabled } + if taskModel.Multi != 1 { + taskModel.Multi = 0 + } taskModel.Spec = form.Spec if id == 0 { id, err = taskModel.Create() diff --git a/service/task.go b/service/task.go index 17070f8..2e53b75 100644 --- a/service/task.go +++ b/service/task.go @@ -15,6 +15,30 @@ import ( ) var Cron *cron.Cron +var runInstance Instance + +// 任务ID作为Key, 不会出现并发读写, 不加锁 +type Instance struct { + Status map[int]bool +} + +// 是否有任务处于运行中 +func (i *Instance) has(key int) bool { + running, ok := i.Status[key] + if ok && running { + return true + } + + return false +} + +func (i *Instance) add(key int) { + i.Status[key] = true +} + +func (i *Instance) done(key int) { + i.Status[key] = false +} type Task struct{} @@ -28,6 +52,7 @@ type TaskResult struct { func (task *Task) Initialize() { Cron = cron.New() Cron.Start() + runInstance = Instance{make(map[int]bool)} taskModel := new(models.Task) taskList, err := taskModel.ActiveList() if err != nil { @@ -159,7 +184,7 @@ func (h *SSHCommandHandler) Run(taskModel models.TaskHost) (string, error) { } // 创建任务日志 -func createTaskLog(taskModel models.TaskHost) (int64, error) { +func createTaskLog(taskModel models.TaskHost, status models.Status) (int64, error) { taskLogModel := new(models.TaskLog) taskLogModel.TaskId = taskModel.Id taskLogModel.Name = taskModel.Task.Name @@ -171,7 +196,7 @@ func createTaskLog(taskModel models.TaskHost) (int64, error) { taskLogModel.Hostname = taskModel.Alias + "-" + taskModel.Name } taskLogModel.StartTime = time.Now() - taskLogModel.Status = models.Running + taskLogModel.Status = status insertId, err := taskLogModel.Create() return insertId, err @@ -202,7 +227,15 @@ func createJob(taskModel models.TaskHost) cron.FuncJob { return nil } taskFunc := func() { - taskLogId, err := createTaskLog(taskModel) + if taskModel.Multi == 0 && runInstance.has(taskModel.Id) { + createTaskLog(taskModel, models.Cancel) + return + } + if taskModel.Multi == 0 { + runInstance.add(taskModel.Id) + defer runInstance.done(taskModel.Id) + } + taskLogId, err := createTaskLog(taskModel, models.Running) if err != nil { logger.Error("任务开始执行#写入任务日志失败-", err) return diff --git a/templates/task/index.html b/templates/task/index.html index c24d5f5..787d2f6 100644 --- a/templates/task/index.html +++ b/templates/task/index.html @@ -63,6 +63,7 @@

命令:{{{.Command}}}

超时时间:{{{if gt .Timeout 0}}}{{{.Timeout}}}秒{{{else}}}不限制{{{end}}}

重试次数: {{{.RetryTimes}}}

+

是否允许多实例:{{{if gt .Multi 0}}}是{{{else}}}否{{{end}}}

{{{if eq .Protocol 2}}}

主机: {{{.Alias}}}

{{{end}}} diff --git a/templates/task/log.html b/templates/task/log.html index 8aa7b75..ebed0a7 100644 --- a/templates/task/log.html +++ b/templates/task/log.html @@ -74,11 +74,13 @@ {{{.RetryTimes}}} {{{.Hostname}}} + {{{if ne .Status 3}}} {{{if gt .TotalTime 0}}}{{{.TotalTime}}}秒{{{else}}}1秒{{{end}}}
开始时间: {{{.StartTime.Format "2006-01-02 15:04:05" }}}
{{{if ne .Status 1}}} 结束时间: {{{.EndTime.Format "2006-01-02 15:04:05" }}} {{{end}}} + {{{end}}} {{{if eq .Status 2}}} @@ -87,12 +89,12 @@ 执行中 {{{else if eq .Status 0}}} 失败 - {{{else}}} - 待执行 + {{{else if eq .Status 3}}} + 取消 {{{end}}} - {{{if ne .Status 1}}} + {{{if and (ne .Status 1) (ne .Status 3)}}}