feat($task): 增加任务标签

pull/21/merge
ouqiang 2017-09-07 21:32:53 +08:00
parent 250cbdde7c
commit c4af1653ff
7 changed files with 62 additions and 44 deletions

View File

@ -49,21 +49,30 @@ func isDatabaseExist(name string) bool {
// 迭代升级数据库, 新建表、新增字段等 // 迭代升级数据库, 新建表、新增字段等
func (migration *Migration) Upgrade(oldVersionId int) { func (migration *Migration) Upgrade(oldVersionId int) {
versionIds := []int{110} // v1.2版本不支持升级
upgradeFuncs := []func(*xorm.Session) error { if oldVersionId == 120 {
migration.upgradeFor110, return
} }
// 默认当前版本为v1.0 versionIds := []int{110, 122}
startIndex := 0 upgradeFuncs := []func(*xorm.Session) error {
migration.upgradeFor110,
migration.upgradeFor122,
}
startIndex := -1
// 从当前版本的下一版本开始升级 // 从当前版本的下一版本开始升级
for i, value := range versionIds { for i, value := range versionIds {
if oldVersionId == value { if value > oldVersionId {
startIndex = i + 1 startIndex = i
break; break;
} }
} }
if startIndex == -1 {
return
}
length := len(versionIds) length := len(versionIds)
if startIndex >= length { if startIndex >= length {
return return
@ -135,3 +144,16 @@ func (migration *Migration) upgradeFor110(session *xorm.Session) error {
return err return err
} }
// 升级到1.2.2版本
func (migration *Migration) upgradeFor122(session *xorm.Session) error {
logger.Info("开始升级到v1.2.2")
tableName := TablePrefix + "task"
// task表增加tag字段
_, err := session.Exec(fmt.Sprintf("ALTER TABLE %s ADD COLUMN tag VARCHAR(32) NOT NULL DEFAULT '' ", tableName))
logger.Info("已升级到v1.2.2\n")
return err
}

View File

@ -44,6 +44,7 @@ type Task struct {
NotifyStatus int8 `xorm:"smallint notnull default 1"` // 任务执行结束是否通知 0: 不通知 1: 失败通知 2: 执行结束通知 NotifyStatus int8 `xorm:"smallint notnull default 1"` // 任务执行结束是否通知 0: 不通知 1: 失败通知 2: 执行结束通知
NotifyType int8 `xorm:"smallint notnull default 0"` // 通知类型 1: 邮件 2: slack NotifyType int8 `xorm:"smallint notnull default 0"` // 通知类型 1: 邮件 2: slack
NotifyReceiverId string `xorm:"varchar(256) notnull default '' "` // 通知接受者ID, setting表主键ID多个ID逗号分隔 NotifyReceiverId string `xorm:"varchar(256) notnull default '' "` // 通知接受者ID, setting表主键ID多个ID逗号分隔
Tag string `xorm:"varchar(32) notnull default ''"`
Remark string `xorm:"varchar(100) notnull default ''"` // 备注 Remark string `xorm:"varchar(100) notnull default ''"` // 备注
Status Status `xorm:"tinyint notnull index default 0"` // 状态 1:正常 0:停止 Status Status `xorm:"tinyint notnull index default 0"` // 状态 1:正常 0:停止
Created time.Time `xorm:"datetime notnull created"` // 创建时间 Created time.Time `xorm:"datetime notnull created"` // 创建时间
@ -73,6 +74,7 @@ func (task *Task) CreateTestTask() {
task.Level = TaskLevelParent task.Level = TaskLevelParent
task.Protocol = TaskHTTP task.Protocol = TaskHTTP
task.Spec = "*/30 * * * * *" task.Spec = "*/30 * * * * *"
task.Tag = "test-task"
// 查询IP地址区域信息 // 查询IP地址区域信息
task.Command = "http://ip.taobao.com/service/getIpInfo.php?ip=117.27.140.253" task.Command = "http://ip.taobao.com/service/getIpInfo.php?ip=117.27.140.253"
task.Status = Enabled task.Status = Enabled
@ -81,7 +83,7 @@ func (task *Task) CreateTestTask() {
func (task *Task) UpdateBean(id int) (int64, error) { func (task *Task) UpdateBean(id int) (int64, error) {
return Db.ID(id). return Db.ID(id).
Cols("name,spec,protocol,command,timeout,multi,retry_times,remark,notify_status,notify_type,notify_receiver_id, dependency_task_id, dependency_status"). Cols("name,spec,protocol,command,timeout,multi,retry_times,remark,notify_status,notify_type,notify_receiver_id, dependency_task_id, dependency_status, tag").
Update(task) Update(task)
} }
@ -261,5 +263,10 @@ func (task *Task) parseWhere(session *xorm.Session, params CommonMap) {
if ok && status.(int) > -1 { if ok && status.(int) > -1 {
session.And("status = ?", status) session.And("status = ?", status)
} }
tag, ok := params["Tag"]
if ok && tag.(string) != "" {
session.And("tag = ? ", tag)
}
} }

View File

@ -120,6 +120,10 @@ func writeConfig(form InstallForm) error {
"app.name", "定时任务管理系统", // 应用名称 "app.name", "定时任务管理系统", // 应用名称
"api.key", "", "api.key", "",
"api.secret", "", "api.secret", "",
"enable_tls", "false",
"ca_file", "",
"cert_file", "",
"key_file", "",
} }
return setting.Write(dbConfig, app.AppConfig) return setting.Write(dbConfig, app.AppConfig)

View File

@ -29,6 +29,7 @@ type TaskForm struct {
Multi int8 `binding:"In(1,2)"` Multi int8 `binding:"In(1,2)"`
RetryTimes int8 RetryTimes int8
HostId string HostId string
Tag string
Remark string Remark string
NotifyStatus int8 `binding:"In(1,2,3)"` NotifyStatus int8 `binding:"In(1,2,3)"`
NotifyType int8 `binding:"In(1,2,3)"` NotifyType int8 `binding:"In(1,2,3)"`
@ -63,8 +64,8 @@ func Index(ctx *macaron.Context) {
if ok { if ok {
safeNameHTML = template.HTMLEscapeString(name) safeNameHTML = template.HTMLEscapeString(name)
} }
PageParams := fmt.Sprintf("id=%d&host_id=%d&name=%s&protocol=%d&status=%d&page_size=%d", PageParams := fmt.Sprintf("id=%d&host_id=%d&name=%s&protocol=%d&tag=%s&status=%d&page_size=%d",
queryParams["Id"], queryParams["HostId"], safeNameHTML, queryParams["Protocol"], queryParams["Status"], queryParams["PageSize"]); queryParams["Id"], queryParams["HostId"], safeNameHTML, queryParams["Protocol"], queryParams["Tag"], queryParams["Status"], queryParams["PageSize"]);
queryParams["PageParams"] = template.URL(PageParams) queryParams["PageParams"] = template.URL(PageParams)
p := paginater.New(int(total), queryParams["PageSize"].(int), queryParams["Page"].(int), 5) p := paginater.New(int(total), queryParams["PageSize"].(int), queryParams["Page"].(int), 5)
ctx.Data["Pagination"] = p ctx.Data["Pagination"] = p
@ -131,6 +132,7 @@ func Store(ctx *macaron.Context, form TaskForm) string {
taskModel.Protocol = form.Protocol taskModel.Protocol = form.Protocol
taskModel.Command = form.Command taskModel.Command = form.Command
taskModel.Timeout = form.Timeout taskModel.Timeout = form.Timeout
taskModel.Tag = form.Tag
taskModel.Remark = form.Remark taskModel.Remark = form.Remark
taskModel.Multi = form.Multi taskModel.Multi = form.Multi
taskModel.RetryTimes = form.RetryTimes taskModel.RetryTimes = form.RetryTimes
@ -301,6 +303,7 @@ func parseQueryParams(ctx *macaron.Context) (models.CommonMap) {
params["HostId"] = ctx.QueryInt("host_id") params["HostId"] = ctx.QueryInt("host_id")
params["Name"] = ctx.QueryTrim("name") params["Name"] = ctx.QueryTrim("name")
params["Protocol"] = ctx.QueryInt("protocol") params["Protocol"] = ctx.QueryInt("protocol")
params["Tag"] = ctx.QueryTrim("tag")
status := ctx.QueryInt("status") status := ctx.QueryInt("status")
if status >=0 { if status >=0 {
status -= 1 status -= 1

View File

@ -14,9 +14,6 @@ import (
rpcClient "github.com/ouqiang/gocron/modules/rpc/client" rpcClient "github.com/ouqiang/gocron/modules/rpc/client"
pb "github.com/ouqiang/gocron/modules/rpc/proto" pb "github.com/ouqiang/gocron/modules/rpc/proto"
"strings" "strings"
"text/template"
"bytes"
"encoding/base64"
) )
// 定时任务调度管理器 // 定时任务调度管理器
@ -304,9 +301,6 @@ func beforeExecJob(taskModel models.Task) (taskLogId int64) {
// 任务执行后置操作 // 任务执行后置操作
func afterExecJob(taskModel models.Task, taskResult TaskResult, taskLogId int64) { func afterExecJob(taskModel models.Task, taskResult TaskResult, taskLogId int64) {
if taskResult.Err != nil {
taskResult.Result = taskResult.Err.Error() + "\n" + taskResult.Result
}
_, err := updateTaskLog(taskLogId, taskResult) _, err := updateTaskLog(taskLogId, taskResult)
if err != nil { if err != nil {
logger.Error("任务结束#更新任务日志失败-", err) logger.Error("任务结束#更新任务日志失败-", err)
@ -349,39 +343,11 @@ func execDependencyTask(taskModel models.Task, taskResult TaskResult) {
} }
serviceTask := new(Task) serviceTask := new(Task)
for _, task := range tasks { for _, task := range tasks {
task.Command = appendResultToCommand(task.Command, taskResult)
task.Spec = fmt.Sprintf("依赖任务(主任务ID-%d)", taskModel.Id) task.Spec = fmt.Sprintf("依赖任务(主任务ID-%d)", taskModel.Id)
serviceTask.Run(task) serviceTask.Run(task)
} }
} }
/**
* , {{.Code}} {{.Message}}
*/
func appendResultToCommand(command string, taskResult TaskResult) string {
var code int8 = 0
if taskResult.Err != nil {
code = 1
}
data := map[string]interface{} {
"Code": code,
"Message": base64.StdEncoding.EncodeToString([]byte(taskResult.Result)),
}
var buf *bytes.Buffer = new(bytes.Buffer)
tmpl, err := template.New("command").Parse(command)
if err != nil {
logger.Errorf("替换子任务命令占位符失败#%s", err.Error())
return command
}
err = tmpl.Execute(buf, data)
if err != nil {
logger.Errorf("替换子任务命令占位符失败#%s", err.Error())
return command
}
return buf.String()
}
// 发送任务结果通知 // 发送任务结果通知
func SendNotification(taskModel models.Task, taskResult TaskResult) { func SendNotification(taskModel models.Task, taskResult TaskResult) {
var statusName string var statusName string

View File

@ -22,6 +22,11 @@
<div class="field"> <div class="field">
<input type="text" placeholder="任务名称" name="name" value="{{{.Params.Name}}}"> <input type="text" placeholder="任务名称" name="name" value="{{{.Params.Name}}}">
</div> </div>
<div class="field">
<input type="text" placeholder="标签名称" name="tag" value="{{{.Params.Tag}}}">
</div>
</div>
<div class="six fields search">
<div class="field"> <div class="field">
<select name="host_id" id="hostId"> <select name="host_id" id="hostId">
<option value=""></option> <option value=""></option>
@ -67,6 +72,7 @@
<th>ID</th> <th>ID</th>
<th></th> <th></th>
<th></th> <th></th>
<th></th>
<th>cron</th> <th>cron</th>
<th></th> <th></th>
<th></th> <th></th>
@ -89,6 +95,7 @@
<td>{{{.Id}}}</td> <td>{{{.Id}}}</td>
<td>{{{.Name}}}</td> <td>{{{.Name}}}</td>
<td>{{{if eq .Level 1}}}{{{else}}}{{{end}}}</td> <td>{{{if eq .Level 1}}}{{{else}}}{{{end}}}</td>
<td>{{{.Tag}}}</td>
<td>{{{.Spec}}}</td> <td>{{{.Spec}}}</td>
<td>{{{if eq .Protocol 1}}} HTTP {{{else if eq .Protocol 2}}} SHELL {{{end}}}</td> <td>{{{if eq .Protocol 1}}} HTTP {{{else if eq .Protocol 2}}} SHELL {{{end}}}</td>
<td>{{{if eq .Timeout -1}}}{{{else if gt .Timeout 0}}}{{{.Timeout}}}{{{else}}}{{{end}}}</td> <td>{{{if eq .Timeout -1}}}{{{else if gt .Timeout 0}}}{{{.Timeout}}}{{{else}}}{{{end}}}</td>

View File

@ -22,6 +22,15 @@
<input type="text" name="name" placeholder="任务名称" value="{{{.Task.Name}}}"> <input type="text" name="name" placeholder="任务名称" value="{{{.Task.Name}}}">
</div> </div>
</div> </div>
<div class="field">
<label>
<div class="content"></div>
</label>
<div class="ui small input">
<input type="text" name="tag" placeholder="标签用于任务分类" value="{{{.Task.Tag}}}">
</div>
</div>
</div> </div>
<div class="two fields"> <div class="two fields">
<div class="field"> <div class="field">