Skip to content

Commit

Permalink
增加WebHook通知,通知模板自定义
Browse files Browse the repository at this point in the history
  • Loading branch information
ouqiang committed May 13, 2018
1 parent 6606f64 commit 06859f3
Show file tree
Hide file tree
Showing 30 changed files with 1,156 additions and 178 deletions.
2 changes: 1 addition & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
.git
nodu_modules
node_modules
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@
* Web框架 [Macaron](http://go-macaron.com/)
* 定时任务调度 [Cron](https://github.com/robfig/cron)
* ORM [Xorm](https://github.com/go-xorm/xorm)
* UI框架 [Semantic UI](https://semantic-ui.com/)
* UI框架 [Element UI](https://github.com/ElemeFE/element)
* 依赖管理 [Govendor](https://github.com/kardianos/govendor)
* RPC框架 [gRPC](https://github.com/grpc/grpc)

Expand All @@ -106,6 +106,15 @@

## ChangeLog

v1.5
--------
* 前端使用Vue+ElementUI重构
* 任务通知
* 新增WebHook通知
* 自定义通知模板
* 匹配任务执行结果关键字发送通知
* 任务列表页显示任务下次执行时间

v1.4
--------
* HTTP任务支持POST请求
Expand Down
Binary file modified assets/screenshot/notification.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/screenshot/task.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
55 changes: 53 additions & 2 deletions internal/models/migration.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ func (migration *Migration) Install(dbName string) error {
}
}
setting.InitBasicField()
task.CreateTestTask()

return nil
}
Expand All @@ -54,12 +53,13 @@ func (migration *Migration) Upgrade(oldVersionId int) {
return
}

versionIds := []int{110, 122, 130, 140}
versionIds := []int{110, 122, 130, 140, 150}
upgradeFuncs := []func(*xorm.Session) error{
migration.upgradeFor110,
migration.upgradeFor122,
migration.upgradeFor130,
migration.upgradeFor140,
migration.upgradeFor150,
}

startIndex := -1
Expand Down Expand Up @@ -192,3 +192,54 @@ func (migration *Migration) upgradeFor140(session *xorm.Session) error {

return err
}

func (m *Migration) upgradeFor150(session *xorm.Session) error {
logger.Info("开始升级到v1.5")

tableName := TablePrefix + "task"
// task表增加字段 notify_keyword
sql := fmt.Sprintf(
"ALTER TABLE %s ADD COLUMN notify_keyword VARCHAR(128) NOT NULL DEFAULT '' ", tableName)
_, err := session.Exec(sql)

if err != nil {
return err
}

settingModel := new(Setting)
settingModel.Code = MailCode
settingModel.Key = MailTemplateKey
settingModel.Value = emailTemplate
_, err = Db.Insert(settingModel)
if err != nil {
return err
}
settingModel.Id = 0
settingModel.Code = SlackCode
settingModel.Key = SlackTemplateKey
settingModel.Value = slackTemplate
_, err = Db.Insert(settingModel)
if err != nil {
return err
}

settingModel.Code = WebhookCode
settingModel.Key = WebhookUrlKey
settingModel.Value = ""
_, err = Db.Insert(settingModel)
if err != nil {
return err
}

settingModel.Code = WebhookCode
settingModel.Key = WebhookTemplateKey
settingModel.Value = webhookTemplate
_, err = Db.Insert(settingModel)
if err != nil {
return err
}

logger.Info("已升级到v1.5\n")

return nil
}
124 changes: 100 additions & 24 deletions internal/models/setting.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ type Setting struct {
}

const slackTemplate = `
任务ID: {{.TaskId}}\n
任务名称: {{.TaskName}}\n
状态: \n {{.Status}} \n
任务ID: {{.TaskId}}
任务名称: {{.TaskName}}
状态: {{.Status}}
执行结果: {{.Result}}
`
const emailTemplate = `
任务ID: {{.TaskId}}<br>
任务名称: {{.TaskName}}<br>
状态: \n {{.Status}}<br>
任务ID: {{.TaskId}}
任务名称: {{.TaskName}}
状态: {{.Status}}
执行结果: {{.Result}}
`
const webhookTemplate = `
Expand All @@ -32,15 +32,25 @@ const webhookTemplate = `
}
`

const SlackCode = "slack"
const SlackUrlKey = "url"
const SlackTemplateKey = "template"
const SlackChannelKey = "channel"
const (
SlackCode = "slack"
SlackUrlKey = "url"
SlackTemplateKey = "template"
SlackChannelKey = "channel"
)

const MailCode = "mail"
const MailTemplateKey = "template"
const MailServerKey = "server"
const MailUserKey = "user"
const (
MailCode = "mail"
MailTemplateKey = "template"
MailServerKey = "server"
MailUserKey = "user"
)

const (
WebhookCode = "webhook"
WebhookTemplateKey = "template"
WebhookUrlKey = "url"
)

// 初始化基本字段 邮件、slack等
func (setting *Setting) InitBasicField() {
Expand All @@ -66,6 +76,18 @@ func (setting *Setting) InitBasicField() {
setting.Key = MailTemplateKey
setting.Value = emailTemplate
Db.Insert(setting)
setting.Id = 0

setting.Code = WebhookCode
setting.Key = WebhookTemplateKey
setting.Value = webhookTemplate
Db.Insert(setting)
setting.Id = 0

setting.Code = WebhookCode
setting.Key = WebhookUrlKey
setting.Value = ""
Db.Insert(setting)
}

// region slack配置
Expand Down Expand Up @@ -109,11 +131,15 @@ func (setting *Setting) formatSlack(list []Setting, slack *Slack) {
}
}

// 更新slack webhook url
func (setting *Setting) UpdateSlackUrl(url string) (int64, error) {
func (setting *Setting) UpdateSlack(url, template string) error {
setting.Value = url

return Db.Cols("value").Update(setting, Setting{Code: SlackCode, Key: SlackUrlKey})
Db.Cols("value").Update(setting, Setting{Code: SlackCode, Key: SlackUrlKey})

setting.Value = template
Db.Cols("value").Update(setting, Setting{Code: SlackCode, Key: SlackTemplateKey})

return nil
}

// 创建slack渠道
Expand Down Expand Up @@ -177,19 +203,28 @@ func (setting *Setting) Mail() (Mail, error) {
func (setting *Setting) formatMail(list []Setting, mail *Mail) {
mailUser := MailUser{}
for _, v := range list {
if v.Key == MailServerKey {
switch v.Key {
case MailServerKey:
json.Unmarshal([]byte(v.Value), mail)
continue
case MailUserKey:
json.Unmarshal([]byte(v.Value), &mailUser)
mailUser.Id = v.Id
mail.MailUsers = append(mail.MailUsers, mailUser)
case MailTemplateKey:
mail.Template = v.Value
}
json.Unmarshal([]byte(v.Value), &mailUser)
mailUser.Id = v.Id
mail.MailUsers = append(mail.MailUsers, mailUser)

}
}

func (setting *Setting) UpdateMailServer(config string) (int64, error) {
func (setting *Setting) UpdateMail(config, template string) error {
setting.Value = config
return Db.Cols("value").Update(setting, Setting{Code: MailCode, Key: MailServerKey})
Db.Cols("value").Update(setting, Setting{Code: MailCode, Key: MailServerKey})

setting.Value = template
Db.Cols("value").Update(setting, Setting{Code: MailCode, Key: MailTemplateKey})

return nil
}

func (setting *Setting) CreateMailUser(username, email string) (int64, error) {
Expand All @@ -212,4 +247,45 @@ func (setting *Setting) RemoveMailUser(id int) (int64, error) {
return Db.Delete(setting)
}

type WebHook struct {
Url string `json:"url"`
Template string `json:"template"`
}

func (setting *Setting) Webhook() (WebHook, error) {
list := make([]Setting, 0)
err := Db.Where("code = ?", WebhookCode).Find(&list)
webHook := WebHook{}
if err != nil {
return webHook, err
}

setting.formatWebhook(list, &webHook)

return webHook, err
}

func (setting *Setting) formatWebhook(list []Setting, webHook *WebHook) {
for _, v := range list {
switch v.Key {
case WebhookUrlKey:
webHook.Url = v.Value
case WebhookTemplateKey:
webHook.Template = v.Value
}

}
}

func (setting *Setting) UpdateWebHook(url, template string) error {
setting.Value = url

Db.Cols("value").Update(setting, Setting{Code: WebhookCode, Key: WebhookUrlKey})

setting.Value = template
Db.Cols("value").Update(setting, Setting{Code: WebhookCode, Key: WebhookTemplateKey})

return nil
}

// endregion
22 changes: 5 additions & 17 deletions internal/models/task.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,18 @@ type Task struct {
Multi int8 `json:"multi" xorm:"tinyint notnull default 1"` // 是否允许多实例运行
RetryTimes int8 `json:"retry_times" xorm:"tinyint notnull default 0"` // 重试次数
RetryInterval int16 `json:"retry_interval" xorm:"smallint notnull default 0"` // 重试间隔时间
NotifyStatus int8 `json:"notify_status" xorm:"tinyint notnull default 1"` // 任务执行结束是否通知 0: 不通知 1: 失败通知 2: 执行结束通知
NotifyType int8 `json:"notify_type" xorm:"tinyint notnull default 0"` // 通知类型 1: 邮件 2: slack
NotifyStatus int8 `json:"notify_status" xorm:"tinyint notnull default 1"` // 任务执行结束是否通知 0: 不通知 1: 失败通知 2: 执行结束通知 3: 任务执行结果关键字匹配通知
NotifyType int8 `json:"notify_type" xorm:"tinyint notnull default 0"` // 通知类型 1: 邮件 2: slack 3: webhook
NotifyReceiverId string `json:"notify_receiver_id" xorm:"varchar(256) notnull default '' "` // 通知接受者ID, setting表主键ID,多个ID逗号分隔
NotifyKeyword string `json:"notify_keyword" xorm:"varchar(128) notnull default '' "`
Tag string `json:"tag" xorm:"varchar(32) notnull default ''"`
Remark string `json:"remark" xorm:"varchar(100) notnull default ''"` // 备注
Status Status `json:"status" xorm:"tinyint notnull index default 0"` // 状态 1:正常 0:停止
Created time.Time `json:"created" xorm:"datetime notnull created"` // 创建时间
Deleted time.Time `json:"deleted" xorm:"datetime deleted"` // 删除时间
BaseModel `json:"-" xorm:"-"`
Hosts []TaskHostDetail `json:"hosts" xorm:"-"`
NextRunTime time.Time `json:"next_run_time" xorm:"-"`
}

func taskHostTableName() []string {
Expand All @@ -77,25 +79,11 @@ func (task *Task) Create() (insertId int, err error) {
return
}

// 新增测试任务
func (task *Task) CreateTestTask() {
// HTTP任务
task.Name = "测试HTTP任务"
task.Level = TaskLevelParent
task.Protocol = TaskHTTP
task.Spec = "*/30 * * * * *"
task.Tag = "test-task"
// 查询IP地址区域信息
task.Command = "http://ip.taobao.com/service/getIpInfo.php?ip=117.27.140.253"
task.Status = Enabled
task.Create()
}

func (task *Task) UpdateBean(id int) (int64, error) {
return Db.ID(id).
Cols(`name,spec,protocol,command,timeout,multi,
retry_times,retry_interval,remark,notify_status,
notify_type,notify_receiver_id, dependency_task_id, dependency_status, tag,http_method`).
notify_type,notify_receiver_id, dependency_task_id, dependency_status, tag,http_method, notify_keyword`).
Update(task)
}

Expand Down
3 changes: 2 additions & 1 deletion internal/modules/notify/mail.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ func (mail *Mail) Send(msg Message) {
logger.Error("#mail#Password为空")
return
}
msg["content"] = parseNotifyTemplate(mailSetting.Template, msg)
toUsers := mail.getActiveMailUsers(mailSetting, msg)
mail.send(mailSetting, toUsers, msg)
}
Expand All @@ -51,7 +52,7 @@ func (mail *Mail) send(mailSetting models.Mail, toUsers []string, msg Message) {
gomailMessage := gomail.NewMessage()
gomailMessage.SetHeader("From", mailSetting.User)
gomailMessage.SetHeader("To", toUsers...)
gomailMessage.SetHeader("Subject", "gocron-定时任务监控通知")
gomailMessage.SetHeader("Subject", "gocron-定时任务通知")
gomailMessage.SetBody("text/html", body)
mailer := gomail.NewPlainDialer(mailSetting.Host, mailSetting.Port,
mailSetting.User, mailSetting.Password)
Expand Down
22 changes: 22 additions & 0 deletions internal/modules/notify/notify.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package notify

import (
"bytes"
"fmt"
"html/template"
"time"

"github.com/ouqiang/gocron/internal/modules/logger"
Expand Down Expand Up @@ -47,7 +49,27 @@ func run() {
// Slack
slack := Slack{}
go slack.Send(msg)
case 3:
// WebHook
webHook := WebHook{}
go webHook.Send(msg)
}
time.Sleep(1 * time.Second)
}
}

func parseNotifyTemplate(notifyTemplate string, msg Message) string {
tmpl, err := template.New("notify").Parse(notifyTemplate)
if err != nil {
return fmt.Sprintf("解析通知模板失败: %s", err)
}
var buf bytes.Buffer
tmpl.Execute(&buf, map[string]interface{}{
"TaskId": msg["task_id"],
"TaskName": msg["name"],
"Status": msg["status"],
"Result": msg["output"],
})

return buf.String()
}
Loading

0 comments on commit 06859f3

Please sign in to comment.