新增配置-任务运行是否允许多实例
parent
a2e4ddf6c5
commit
e46a138ac5
|
@ -4,7 +4,7 @@
|
|||
|
||||
## 安装, 解压后执行
|
||||
```shell
|
||||
Windows ./gocron.exe web
|
||||
Windows gocron.exe web
|
||||
Linux、OSX ./gocron web
|
||||
```
|
||||
可选参数
|
||||
|
|
|
@ -21,6 +21,7 @@ const (
|
|||
Enabled Status = 1 // 启用
|
||||
Running Status = 1 // 运行中
|
||||
Finish Status = 2 // 完成
|
||||
Cancel Status = 3 // 取消
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
// 更新
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
<p class="sensorStatus">命令:{{{.Command}}}</p>
|
||||
<p class="sensorStatus">超时时间:{{{if gt .Timeout 0}}}{{{.Timeout}}}秒{{{else}}}不限制{{{end}}}</p>
|
||||
<p>重试次数: {{{.RetryTimes}}}</p>
|
||||
<p class="sensorStatus">是否允许多实例:{{{if gt .Multi 0}}}是{{{else}}}否{{{end}}}</p>
|
||||
{{{if eq .Protocol 2}}}
|
||||
<p>主机: {{{.Alias}}}</p>
|
||||
{{{end}}}
|
||||
|
|
|
@ -74,11 +74,13 @@
|
|||
<td>{{{.RetryTimes}}}</td>
|
||||
<td>{{{.Hostname}}}</td>
|
||||
<td>
|
||||
{{{if ne .Status 3}}}
|
||||
{{{if gt .TotalTime 0}}}{{{.TotalTime}}}秒{{{else}}}1秒{{{end}}}<br>
|
||||
开始时间: {{{.StartTime.Format "2006-01-02 15:04:05" }}}<br>
|
||||
{{{if ne .Status 1}}}
|
||||
结束时间: {{{.EndTime.Format "2006-01-02 15:04:05" }}}
|
||||
{{{end}}}
|
||||
{{{end}}}
|
||||
</td>
|
||||
<td>
|
||||
{{{if eq .Status 2}}}
|
||||
|
@ -87,12 +89,12 @@
|
|||
<span style="color:green">执行中</span>
|
||||
{{{else if eq .Status 0}}}
|
||||
<span style="color:red">失败</span>
|
||||
{{{else}}}
|
||||
<span style="color:#4499EE">待执行</span>
|
||||
{{{else if eq .Status 3}}}
|
||||
<span style="color:#4499EE">取消</span>
|
||||
{{{end}}}
|
||||
</td>
|
||||
<td>
|
||||
{{{if ne .Status 1}}}
|
||||
{{{if and (ne .Status 1) (ne .Status 3)}}}
|
||||
<button class="ui small primary button"
|
||||
onclick="showResult('{{{.Name}}}', '{{{.Command}}}', '{{{.Result}}}')"
|
||||
>查看结果
|
||||
|
|
|
@ -110,6 +110,15 @@
|
|||
<input type="text" name="timeout" value="{{{.Task.Timeout}}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="three fields">
|
||||
<div class="field">
|
||||
<label>允许多实例运行</label>
|
||||
<select name="multi">
|
||||
<option value="1"{{{if .Task}}} {{{if eq .Task.Multi 1}}}selected{{{end}}} {{{end}}}>是</option>
|
||||
<option value="2" {{{if .Task}}} {{{if eq .Task.Multi 0}}}selected{{{end}}} {{{end}}}>否</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="three fields">
|
||||
<div class="field">
|
||||
<label>任务状态</label>
|
||||
|
@ -117,7 +126,7 @@
|
|||
任务添加成功后,是否立即调度
|
||||
</div>
|
||||
<select name="status">
|
||||
<option value="2"{{{if .Task}}} {{{if eq .Task.Status 2}}}selected{{{end}}} {{{end}}}>暂停</option>
|
||||
<option value="2"{{{if .Task}}} {{{if eq .Task.Status 0}}}selected{{{end}}} {{{end}}}>暂停</option>
|
||||
<option value="1" {{{if .Task}}} {{{if eq .Task.Status 1}}}selected{{{end}}} {{{end}}}>激活</option>
|
||||
</select>
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue