mirror of
https://github.com/ouqiang/gocron.git
synced 2024-04-21 12:31:58 +00:00
Compare commits
21
Commits
v0.0.1-beta
...
v0.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6cd09d7f38 | ||
|
|
0f5c4c3e2a | ||
|
|
428275f813 | ||
|
|
0be9269b8c | ||
|
|
f699a72c28 | ||
|
|
70bccfaea0 | ||
|
|
0bc4070762 | ||
|
|
0dfa998d11 | ||
|
|
1b4a6e8c62 | ||
|
|
190cae9ae7 | ||
|
|
d1ecbd9043 | ||
|
|
55060aca67 | ||
|
|
2b2d4b237d | ||
|
|
5276fb9074 | ||
|
|
98bf5ee058 | ||
|
|
95ea60f23c | ||
|
|
6f76d3b17e | ||
|
|
85996077ec | ||
|
|
7c3f6a58d4 | ||
|
|
bf07c6e2e2 | ||
|
|
b2ad507010 |
+1
-2
@@ -1,5 +1,4 @@
|
||||
language: go
|
||||
go:
|
||||
- 1.7.x
|
||||
- 1.8.x
|
||||
- master
|
||||
script: go test `go list ./... | grep -v vendor`
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 qiang.ou
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
## 功能特性
|
||||
* 支持任务CURD
|
||||
* crontab时间表达式,可精确到每秒
|
||||
* crontab时间表达式,精确到秒
|
||||
* 任务执行失败重试设置
|
||||
* 任务超时设置
|
||||
* 任务执行方式
|
||||
@@ -21,28 +21,31 @@
|
||||

|
||||
|
||||
### 支持平台
|
||||
> Windows、Linux、OSX
|
||||
> Windows、Linux、Mac OS
|
||||
|
||||
### 环境要求
|
||||
> MySQL
|
||||
|
||||
|
||||
## 下载
|
||||
* [Linux-64位](http://opns468ov.bkt.clouddn.com/gocron/gocron-linux-amd64.tar.gz)
|
||||
* [Mac OS-64位](http://opns468ov.bkt.clouddn.com/gocron/gocron-darwin-amd64.tar.gz)
|
||||
* [Windows-64位](http://opns468ov.bkt.clouddn.com/gocron/gocron-windows-amd64.zip)
|
||||
|
||||
## 安装
|
||||
|
||||
|
||||
### 二进制安装
|
||||
1. [下载](https://pan.baidu.com/s/1pLNRndx#list/path=%2Fgocron), 解压压缩包
|
||||
1. 解压压缩包
|
||||
2. `cd 解压目录`
|
||||
3. 启动
|
||||
* Windows: `gocron.exe web`
|
||||
* Linux、OSX: `./gocron web`
|
||||
* Linux、Mac OS: `./gocron web`
|
||||
4. 浏览器访问 http://localhost:5920
|
||||
### 源码安装
|
||||
1. `go`语言版本1.7+
|
||||
2. `go get -d https://github.com/ouqiang/gocron`
|
||||
2. `go get -d github.com/ouqiang/gocron`
|
||||
3. 编译 `go build`
|
||||
4. 启动、访问方式同上
|
||||
5. 生成压缩包(Windows: gocron.zip, 其他平台: gocron.tar.gz)
|
||||
> ./build.sh -p 平台 -a CPU架构 例 ./build.sh -p darwin -a amd64
|
||||
|
||||
### 启动可选参数
|
||||
|
||||
@@ -54,3 +57,13 @@
|
||||
* 使用`https`访问保证数据传输安全, 可在web服务器如nginx中配置https,通过反向代理,访问内部的gocron
|
||||
* 网站访问设置IP白名单
|
||||
* SSH登录设置IP白名单
|
||||
|
||||
## 程序使用的组件
|
||||
* 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/)
|
||||
* 依赖管理(所有依赖包放入vendor目录) [govendor](https://github.com/kardianos/govendor)
|
||||
|
||||
## 贡献
|
||||
欢迎提交PR
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
# 构建应用, 生成压缩包 gocron.zip或gocron.tar.gz
|
||||
# ./build.sh -p windows -a amd64
|
||||
# 参数含义
|
||||
# -p 指定平台(widows|linux|darwin)
|
||||
# -p 指定平台(windows|linux|darwin)
|
||||
# -a 指定体系架构(amd64|386), 默认amd64
|
||||
|
||||
|
||||
|
||||
+6
-3
@@ -93,12 +93,12 @@ func setEnvironment(ctx *cli.Context) {
|
||||
}
|
||||
|
||||
switch env {
|
||||
case "prod":
|
||||
macaron.Env = macaron.PROD
|
||||
case "test":
|
||||
macaron.Env = macaron.TEST
|
||||
case "dev":
|
||||
macaron.Env = macaron.DEV
|
||||
default:
|
||||
macaron.Env = macaron.PROD
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,12 +124,15 @@ func shutdown() {
|
||||
os.Exit(0)
|
||||
return
|
||||
}
|
||||
logger.Info("应用准备退出\n停止任务调度")
|
||||
logger.Info("应用准备退出, 停止任务调度")
|
||||
serviceTask := new(service.Task)
|
||||
// 停止所有任务调度
|
||||
serviceTask.StopAll()
|
||||
taskNumInRunning := service.TaskNum.Num()
|
||||
logger.Infof("正在运行的任务有%d个", taskNumInRunning)
|
||||
if taskNumInRunning > 0 {
|
||||
logger.Info("等待所有任务执行完成后退出")
|
||||
}
|
||||
for {
|
||||
if taskNumInRunning <= 0 {
|
||||
break
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
"github.com/ouqiang/gocron/cmd"
|
||||
)
|
||||
|
||||
const AppVersion = "0.0.1"
|
||||
const AppVersion = "0.1"
|
||||
|
||||
func main() {
|
||||
app := cli.NewApp()
|
||||
|
||||
+3
-1
@@ -13,8 +13,9 @@ func (migration *Migration) Exec(dbName string) error {
|
||||
return errors.New("数据库不存在")
|
||||
}
|
||||
setting := new(Setting)
|
||||
task := new(Task)
|
||||
tables := []interface{}{
|
||||
&User{}, &Task{}, &TaskLog{}, &Host{}, setting,&LoginLog{},
|
||||
&User{}, task, &TaskLog{}, &Host{}, setting,&LoginLog{},
|
||||
}
|
||||
for _, table := range tables {
|
||||
exist, err:= Db.IsTableExist(table)
|
||||
@@ -30,6 +31,7 @@ func (migration *Migration) Exec(dbName string) error {
|
||||
}
|
||||
}
|
||||
setting.InitBasicField()
|
||||
task.CreateTestTask()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
+28
-2
@@ -4,6 +4,7 @@ import (
|
||||
"time"
|
||||
"github.com/ouqiang/gocron/modules/ssh"
|
||||
"github.com/go-xorm/xorm"
|
||||
"github.com/ouqiang/gocron/modules/utils"
|
||||
)
|
||||
|
||||
type TaskProtocol int8
|
||||
@@ -29,9 +30,9 @@ type Task struct {
|
||||
NotifyType int8 `xorm:"smallint notnull default 0"` // 通知类型 1: 邮件 2: slack
|
||||
NotifyReceiverId string `xorm:"varchar(256) notnull default '' "` // 通知接受者ID, setting表主键ID,多个ID逗号分隔
|
||||
Remark string `xorm:"varchar(100) notnull default ''"` // 备注
|
||||
Status Status `xorm:"tinyint notnull default 0"` // 状态 1:正常 0:停止
|
||||
Created time.Time `xorm:"datetime notnull created"` // 创建时间
|
||||
Deleted time.Time `xorm:"datetime deleted"` // 删除时间
|
||||
Status Status `xorm:"tinyint notnull default 1"` // 状态 1:正常 0:停止
|
||||
BaseModel `xorm:"-"`
|
||||
}
|
||||
|
||||
@@ -58,8 +59,33 @@ func (task *Task) Create() (insertId int, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// 新增测试任务
|
||||
func (task *Task) CreateTestTask() {
|
||||
// HTTP任务
|
||||
task.Name = "测试HTTP任务"
|
||||
task.Protocol = TaskHTTP
|
||||
task.Spec = "*/30 * * * * *"
|
||||
// 查询IP地址区域信息
|
||||
task.Command = "http://ip.taobao.com/service/getIpInfo.php?ip=117.27.140.253"
|
||||
task.Status = Enabled
|
||||
task.Create()
|
||||
|
||||
// 系统命令
|
||||
task.Id = 0
|
||||
task.Name = "测试系统命令任务"
|
||||
task.Protocol = TaskLocalCommand
|
||||
task.Spec = "@every 1m"
|
||||
task.Status = Enabled
|
||||
if utils.IsWindows() {
|
||||
task.Command = "dir"
|
||||
} else {
|
||||
task.Command = "ls"
|
||||
}
|
||||
task.Create()
|
||||
}
|
||||
|
||||
func (task *Task) UpdateBean(id int) (int64, error) {
|
||||
return Db.ID(id).Cols("name,spec,protocol,command,timeout,multi,retry_times,host_id,remark,status,notify_status,notify_type,notify_receiver_id").Update(task)
|
||||
return Db.ID(id).Cols("name,spec,protocol,command,timeout,multi,retry_times,host_id,remark,notify_status,notify_type,notify_receiver_id").Update(task)
|
||||
}
|
||||
|
||||
// 更新
|
||||
|
||||
+19
-2
@@ -72,9 +72,26 @@ func (taskLog *TaskLog) List(params CommonMap) ([]TaskLog, error) {
|
||||
return list, err
|
||||
}
|
||||
|
||||
// 根据通知ID获取任务ID
|
||||
func (taskLog *TaskLog) GetTaskIdByNotifyId(notifyId string) (taskId int, err error) {
|
||||
exist, err := Db.Where("notify_id = ?", notifyId).Get(taskLog)
|
||||
if !exist || err != nil {
|
||||
return
|
||||
}
|
||||
taskId = taskLog.TaskId
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 清空表
|
||||
func (TaskLog *TaskLog) Clear() (int64, error) {
|
||||
return Db.Where("1=1").Delete(TaskLog);
|
||||
func (taskLog *TaskLog) Clear() (int64, error) {
|
||||
return Db.Where("1=1").Delete(taskLog);
|
||||
}
|
||||
|
||||
// 删除N个月前的日志
|
||||
func (taskLog *TaskLog) Remove(id int) (int64, error) {
|
||||
t := time.Now().AddDate(0, -id, 0)
|
||||
return Db.Where("start_time <= ?", t.Format(DefaultTimeFormat)).Delete(taskLog)
|
||||
}
|
||||
|
||||
func (taskLog *TaskLog) Total(params CommonMap) (int64, error) {
|
||||
|
||||
@@ -66,7 +66,7 @@ func (mail *Mail) send(mailSetting models.Mail, toUsers []string, msg Message)
|
||||
i += 1
|
||||
time.Sleep(2 * time.Second)
|
||||
if i < maxTimes {
|
||||
logger.Error("mail#发送消息失败#%s#消息内容-%s", err.Error(), msg["content"])
|
||||
logger.Errorf("mail#发送消息失败#%s#消息内容-%s", err.Error(), msg["content"])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ func (slack *Slack) send(msg Message, slackUrl string, channel string) {
|
||||
i += 1
|
||||
time.Sleep(2 * time.Second)
|
||||
if i < maxTimes {
|
||||
logger.Error("slack#发送消息失败#%s#消息内容-%s", resp.Body, msg["content"])
|
||||
logger.Errorf("slack#发送消息失败#%s#消息内容-%s", resp.Body, msg["content"])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,6 +105,14 @@ func UpdateMailServer(ctx *macaron.Context, form MailServerForm) string {
|
||||
return utils.JsonResponseByErr(err)
|
||||
}
|
||||
|
||||
func ClearMailServer(ctx *macaron.Context) string {
|
||||
jsonByte, _ := json.Marshal(MailServerForm{})
|
||||
settingModel := new(models.Setting)
|
||||
_, err := settingModel.UpdateMailServer(string(jsonByte))
|
||||
|
||||
return utils.JsonResponseByErr(err)
|
||||
}
|
||||
|
||||
func CreateMailUser(ctx *macaron.Context) string {
|
||||
username := ctx.QueryTrim("username")
|
||||
email := ctx.QueryTrim("email")
|
||||
|
||||
+9
-3
@@ -80,6 +80,7 @@ func Register(m *macaron.Macaron) {
|
||||
m.Get("/", manage.Mail)
|
||||
m.Get("/edit", manage.EditMail)
|
||||
m.Post("/server", binding.Bind(manage.MailServerForm{}), manage.UpdateMailServer)
|
||||
m.Post("/server/clear", manage.ClearMailServer)
|
||||
m.Post("/user", manage.CreateMailUser)
|
||||
m.Post("/user/remove/:id", manage.RemoveMailUser)
|
||||
})
|
||||
@@ -88,7 +89,8 @@ func Register(m *macaron.Macaron) {
|
||||
|
||||
// API
|
||||
m.Group("/api/v1", func() {
|
||||
m.Get("/tasklog/update-status", tasklog.UpdateStatus)
|
||||
m.Route("/tasklog/update-status", "GET,POST", tasklog.UpdateStatus)
|
||||
m.Post("/tasklog/remove/:id", tasklog.Remove)
|
||||
});
|
||||
|
||||
// 404错误
|
||||
@@ -149,7 +151,9 @@ func RegisterMiddleware(m *macaron.Macaron) {
|
||||
})
|
||||
}
|
||||
|
||||
// 系统未安装,重定向到安装页面
|
||||
// region 自定义中间件
|
||||
|
||||
/** 系统未安装,重定向到安装页面 **/
|
||||
func checkAppInstall(m *macaron.Macaron) {
|
||||
m.Use(func(ctx *macaron.Context) {
|
||||
installUrl := "/install"
|
||||
@@ -195,7 +199,9 @@ func userAuth(ctx *macaron.Context, sess session.Store) {
|
||||
}
|
||||
}
|
||||
|
||||
// 设置共享数据
|
||||
// endregion
|
||||
|
||||
/** 设置共享数据 **/
|
||||
func setShareData(ctx *macaron.Context, sess session.Store) {
|
||||
ctx.Data["URI"] = ctx.Req.URL.Path
|
||||
urlPath := strings.TrimPrefix(ctx.Req.URL.Path, "/")
|
||||
|
||||
+21
-27
@@ -13,6 +13,7 @@ import (
|
||||
"html/template"
|
||||
"github.com/ouqiang/gocron/routers/base"
|
||||
"github.com/go-macaron/binding"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type TaskForm struct {
|
||||
@@ -26,7 +27,6 @@ type TaskForm struct {
|
||||
RetryTimes int8
|
||||
HostId int16
|
||||
Remark string
|
||||
Status models.Status `binding:"In(1,2)"`
|
||||
NotifyStatus int8 `binding:In(1,2,3)`
|
||||
NotifyType int8 `binding:In(1,2)`
|
||||
NotifyReceiverId string
|
||||
@@ -82,11 +82,6 @@ func Create(ctx *macaron.Context) {
|
||||
// 编辑页面
|
||||
func Edit(ctx *macaron.Context) {
|
||||
id := ctx.ParamsInt(":id")
|
||||
hostModel := new(models.Host)
|
||||
hosts, err := hostModel.List(models.CommonMap{})
|
||||
if err != nil || len(hosts) == 0 {
|
||||
logger.Error(err)
|
||||
}
|
||||
taskModel := new(models.Task)
|
||||
task, err := taskModel.Detail(id)
|
||||
if err != nil || task.Id != id {
|
||||
@@ -95,11 +90,7 @@ func Edit(ctx *macaron.Context) {
|
||||
}
|
||||
ctx.Data["Task"] = task
|
||||
ctx.Data["Title"] = "编辑"
|
||||
ctx.Data["Hosts"] = hosts
|
||||
if len(hosts) > 0 {
|
||||
ctx.Data["FirstHostName"] = hosts[0].Name
|
||||
ctx.Data["FirstHostId"] = hosts[0].Id
|
||||
}
|
||||
setHostsToTemplate(ctx)
|
||||
ctx.HTML(200, "task/task_form")
|
||||
}
|
||||
|
||||
@@ -134,12 +125,8 @@ func Store(ctx *macaron.Context, form TaskForm) string {
|
||||
taskModel.Command = form.Command
|
||||
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
|
||||
}
|
||||
@@ -148,14 +135,30 @@ func Store(ctx *macaron.Context, form TaskForm) string {
|
||||
taskModel.NotifyReceiverId = form.NotifyReceiverId
|
||||
taskModel.Spec = form.Spec
|
||||
if taskModel.NotifyStatus > 0 && taskModel.NotifyReceiverId == "" {
|
||||
return json.CommonFailure("请至少选择一个接收者", err)
|
||||
return json.CommonFailure("请至少选择一个接收者")
|
||||
}
|
||||
if taskModel.Protocol == models.TaskHTTP && taskModel.Timeout == -1 {
|
||||
return json.CommonFailure("HTTP任务不支持后台运行", err)
|
||||
if taskModel.Protocol == models.TaskHTTP {
|
||||
command := strings.ToLower(taskModel.Command)
|
||||
if !strings.HasPrefix(command, "http://") && !strings.HasPrefix(command, "https://") {
|
||||
return json.CommonFailure("请输入正确的URL地址")
|
||||
}
|
||||
if taskModel.Timeout == -1 {
|
||||
return json.CommonFailure("HTTP任务不支持后台运行")
|
||||
}
|
||||
if taskModel.Timeout > 300 {
|
||||
return json.CommonFailure("HTTP任务超时时间不能超过300秒")
|
||||
}
|
||||
}
|
||||
|
||||
if taskModel.RetryTimes > 10 || taskModel.RetryTimes < 0 {
|
||||
return json.CommonFailure("任务重试次数取值0-10")
|
||||
}
|
||||
|
||||
|
||||
if taskModel.Protocol != models.TaskSSH {
|
||||
taskModel.HostId = 0
|
||||
}
|
||||
|
||||
if id == 0 {
|
||||
id, err = taskModel.Create()
|
||||
} else {
|
||||
@@ -165,11 +168,6 @@ func Store(ctx *macaron.Context, form TaskForm) string {
|
||||
return json.CommonFailure("保存失败", err)
|
||||
}
|
||||
|
||||
// 任务处于激活状态,加入调度管理
|
||||
if (taskModel.Status == models.Enabled) {
|
||||
addTaskToTimer(id)
|
||||
}
|
||||
|
||||
return json.Success("保存成功", nil)
|
||||
}
|
||||
|
||||
@@ -273,8 +271,4 @@ func setHostsToTemplate(ctx *macaron.Context) {
|
||||
logger.Error(err)
|
||||
}
|
||||
ctx.Data["Hosts"] = hosts
|
||||
if len(hosts) > 0 {
|
||||
ctx.Data["FirstHostName"] = hosts[0].Name
|
||||
ctx.Data["FirstHostId"] = hosts[0].Id
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package tasklog
|
||||
|
||||
// 任务日志
|
||||
|
||||
import (
|
||||
"gopkg.in/macaron.v1"
|
||||
"github.com/ouqiang/gocron/models"
|
||||
@@ -9,11 +11,10 @@ import (
|
||||
"fmt"
|
||||
"html/template"
|
||||
"github.com/ouqiang/gocron/routers/base"
|
||||
"github.com/ouqiang/gocron/service"
|
||||
"errors"
|
||||
)
|
||||
|
||||
// @author qiang.ou<qingqianludao@gmail.com>
|
||||
// @date 2017/4/7-21:18
|
||||
|
||||
func Index(ctx *macaron.Context) {
|
||||
logModel := new(models.TaskLog)
|
||||
queryParams := parseQueryParams(ctx)
|
||||
@@ -49,12 +50,29 @@ func Clear(ctx *macaron.Context) string {
|
||||
return json.Success(utils.SuccessContent, nil)
|
||||
}
|
||||
|
||||
// 删除N个月前的日志
|
||||
func Remove(ctx *macaron.Context) string {
|
||||
month := ctx.ParamsInt(":id")
|
||||
json := utils.JsonResponse{}
|
||||
if month < 1 || month > 12 {
|
||||
return json.CommonFailure("参数取值范围1-12")
|
||||
}
|
||||
taskLogModel := new(models.TaskLog)
|
||||
_, err := taskLogModel.Remove(month)
|
||||
if err != nil {
|
||||
return json.CommonFailure("删除失败", err)
|
||||
}
|
||||
|
||||
return json.Success("删除成功", nil)
|
||||
}
|
||||
|
||||
// 更新任务状态
|
||||
func UpdateStatus(ctx *macaron.Context) string {
|
||||
id := ctx.QueryTrim("id")
|
||||
status := ctx.QueryInt("status")
|
||||
result := ctx.QueryTrim("result")
|
||||
json := utils.JsonResponse{}
|
||||
|
||||
if id == "" {
|
||||
return json.CommonFailure("任务ID不能为空")
|
||||
}
|
||||
@@ -70,6 +88,26 @@ func UpdateStatus(ctx *macaron.Context) string {
|
||||
return json.CommonFailure("更新任务状态失败")
|
||||
}
|
||||
|
||||
// 发送通知
|
||||
taskId, err := taskLogModel.GetTaskIdByNotifyId(id)
|
||||
if err != nil || taskId <= 0 {
|
||||
logger.Error("异步任务回调#根据notify-id获取taskId失败", err)
|
||||
return json.Success("success", nil)
|
||||
}
|
||||
taskModel := new(models.Task)
|
||||
task, err := taskModel.Detail(taskId)
|
||||
if err != nil || task.Id <= 0 {
|
||||
logger.Error("异步任务回调#根据获取任务详情失败", err)
|
||||
return json.Success("success", nil)
|
||||
}
|
||||
|
||||
taskResult := service.TaskResult{}
|
||||
taskResult.Result = result
|
||||
if status == 0 {
|
||||
taskResult.Err = errors.New("error")
|
||||
}
|
||||
service.SendNotification(task, taskResult)
|
||||
|
||||
return json.Success("success", nil)
|
||||
}
|
||||
|
||||
|
||||
+13
-2
@@ -173,7 +173,13 @@ func (h *LocalCommandHandler) runOnUnix(taskModel models.TaskHost) (string, erro
|
||||
// HTTP任务
|
||||
type HTTPHandler struct{}
|
||||
|
||||
// http任务执行时间不超过300秒
|
||||
const HttpExecTimeout = 300
|
||||
|
||||
func (h *HTTPHandler) Run(taskModel models.TaskHost) (result string, err error) {
|
||||
if taskModel.Timeout <= 0 || taskModel.Timeout > HttpExecTimeout {
|
||||
taskModel.Timeout = HttpExecTimeout
|
||||
}
|
||||
resp := httpclient.Get(taskModel.Command, taskModel.Timeout)
|
||||
// 返回状态码非200,均为失败
|
||||
if resp.StatusCode != 200 {
|
||||
@@ -274,7 +280,9 @@ func createJob(taskModel models.TaskHost) cron.FuncJob {
|
||||
if taskLogId <= 0 {
|
||||
return
|
||||
}
|
||||
logger.Infof("开始执行任务#%s#命令-%s", taskModel.Task.Name, taskModel.Command)
|
||||
taskResult := execJob(handler, taskModel)
|
||||
logger.Infof("任务完成#%s#命令-%s", taskModel.Task.Name, taskModel.Command)
|
||||
afterExecJob(taskModel, taskResult, taskLogId)
|
||||
}
|
||||
|
||||
@@ -338,11 +346,11 @@ func afterExecJob(taskModel models.TaskHost, taskResult TaskResult, taskLogId in
|
||||
return
|
||||
}
|
||||
|
||||
sendNotification(taskModel, taskResult)
|
||||
SendNotification(taskModel, taskResult)
|
||||
}
|
||||
|
||||
// 发送任务结果通知
|
||||
func sendNotification(taskModel models.TaskHost, taskResult TaskResult) {
|
||||
func SendNotification(taskModel models.TaskHost, taskResult TaskResult) {
|
||||
var statusName string
|
||||
// 未开启通知
|
||||
if taskModel.NotifyStatus == 0 {
|
||||
@@ -352,6 +360,9 @@ func sendNotification(taskModel models.TaskHost, taskResult TaskResult) {
|
||||
// 执行失败才发送通知
|
||||
return
|
||||
}
|
||||
if taskModel.NotifyReceiverId == "" {
|
||||
return
|
||||
}
|
||||
if taskResult.Err != nil {
|
||||
statusName = "失败"
|
||||
} else {
|
||||
|
||||
@@ -68,6 +68,7 @@
|
||||
</div>
|
||||
|
||||
<div class="ui primary submit button">保存</div>
|
||||
<a class="ui button" onclick="location.href='/task';">取消</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -90,9 +90,17 @@
|
||||
$('.ui.form').form(
|
||||
{
|
||||
onSuccess: function(event, fields) {
|
||||
swal({
|
||||
title: '',
|
||||
text: "系统安装中.......",
|
||||
type: 'info',
|
||||
showConfirmButton: false
|
||||
});
|
||||
util.post('/install/store', fields, function(code, message) {
|
||||
swal('安装成功');
|
||||
location.href = "/";
|
||||
setTimeout(function() {
|
||||
location.href = "/";
|
||||
}, 2000)
|
||||
});
|
||||
return false;
|
||||
},
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<div class="four fields">
|
||||
<div class="field">
|
||||
<label>
|
||||
主机名
|
||||
SMTP服务器
|
||||
</label>
|
||||
<div class="ui small input">
|
||||
<input type="text" name="host" value="{{{.Mail.Host}}}">
|
||||
@@ -48,6 +48,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<button class="ui primary button">保存</button>
|
||||
{{{if .Mail.Host}}}
|
||||
<a class="ui green button" onclick="clearMailServer()">删除</a>
|
||||
{{{end}}}
|
||||
<br><br><br>
|
||||
<div>
|
||||
<div class="content">邮箱用户</div><p></p>
|
||||
@@ -98,7 +101,7 @@
|
||||
util.post('/manage/mail/server',
|
||||
fields,
|
||||
function(code, message) {
|
||||
util.alertSuccess();
|
||||
location.reload();
|
||||
}
|
||||
);
|
||||
return false;
|
||||
@@ -188,5 +191,11 @@
|
||||
location.reload();
|
||||
});
|
||||
}
|
||||
|
||||
function clearMailServer() {
|
||||
util.post('/manage/mail/server/clear', {}, function(code, message) {
|
||||
location.reload();
|
||||
});
|
||||
}
|
||||
</script>
|
||||
{{{ template "common/footer" . }}}
|
||||
@@ -62,7 +62,7 @@
|
||||
<p>cron表达式: {{{.Spec}}}</p>
|
||||
<p>执行方式: {{{if eq .Protocol 1}}} HTTP {{{else if eq .Protocol 2}}} SSH {{{else if eq .Protocol 3}}}本地命令{{{end}}}</p>
|
||||
<p class="sensorStatus">命令:{{{.Command}}}</p>
|
||||
<p class="sensorStatus">超时时间:{{{if eq .Timeout -1}}}后台运行{{{else if eq .Timeout 0}}}{{{.Timeout}}}秒{{{else}}}不限制{{{end}}}</p>
|
||||
<p class="sensorStatus">超时时间:{{{if eq .Timeout -1}}}后台运行{{{else 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}}}
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
<td>{{{.Name}}}</td>
|
||||
<td>{{{.Spec}}}</td>
|
||||
<td>{{{if eq .Protocol 1}}} HTTP {{{else if eq .Protocol 2}}} SSH {{{else}}} 系统命令 {{{end}}}</td>
|
||||
<td>{{{if eq .Timeout -1}}}后台运行{{{else if eq .Timeout 0}}}{{{.Timeout}}}秒{{{else}}}不限制{{{end}}}</td>
|
||||
<td>{{{if eq .Timeout -1}}}后台运行{{{else if gt .Timeout 0}}}{{{.Timeout}}}秒{{{else}}}不限制{{{end}}}</td>
|
||||
<td>{{{.RetryTimes}}}</td>
|
||||
<td>{{{.Hostname}}}</td>
|
||||
<td>
|
||||
@@ -98,7 +98,7 @@
|
||||
{{{end}}}
|
||||
</td>
|
||||
<td>
|
||||
{{{if and (ne .Status 1) (ne .Status 3)}}}
|
||||
{{{if or (eq .Status 2) (eq .Status 0)}}}
|
||||
<button class="ui small primary button"
|
||||
onclick="showResult('{{{.Name}}}', '{{{.Command}}}', '{{{.Result}}}')"
|
||||
>查看结果
|
||||
|
||||
@@ -56,14 +56,14 @@
|
||||
{{{range $i, $v := .Hosts}}}
|
||||
<option value="{{{.Id}}}" {{{if $.Task}}}{{{if eq $.Task.HostId .Id }}} selected {{{end}}} {{{end}}}>{{{.Alias}}}-{{{.Name}}}</option>
|
||||
{{{end}}}
|
||||
</select> <a class="ui blue button" href="/host/create">添加主机</a>
|
||||
</select> <a class="ui blue button" href="/host/create" target="_blank">添加主机</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="two fields">
|
||||
<div class="field">
|
||||
<label>命令</label>
|
||||
<textarea rows="5" name="command">{{{.Task.Command}}}</textarea>
|
||||
<textarea rows="5" name="command" placeholder="请输入系统命令" id="command">{{{.Task.Command}}}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="six fields">
|
||||
@@ -81,27 +81,12 @@
|
||||
<div class="three fields">
|
||||
<div class="field">
|
||||
<label>允许多实例同时运行</label>
|
||||
<div class="ui blue message">
|
||||
前次任务未执行完成,本次任务是否执行
|
||||
</div>
|
||||
<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>
|
||||
<div class="ui blue message">
|
||||
任务添加成功后,是否立即调度
|
||||
</div>
|
||||
<select name="status">
|
||||
<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>
|
||||
</div>
|
||||
<div class="three fields">
|
||||
<div class="field">
|
||||
<label>任务通知</label>
|
||||
@@ -129,7 +114,7 @@
|
||||
<textarea rows="5" name="remark">{{{.Task.Remark}}}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui primary submit button">保存</div>
|
||||
<div class="ui primary submit button">保存</div> <a class="ui button" onclick="location.href='/task';">取消</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -162,14 +147,18 @@
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
changeCommandPlaceholder();
|
||||
changeProtocol();
|
||||
showNotify();
|
||||
});
|
||||
|
||||
$('#protocol').change(function() {
|
||||
changeProtocol();
|
||||
changeCommandPlaceholder();
|
||||
changeProtocol();
|
||||
});
|
||||
|
||||
|
||||
|
||||
$('#task-status').change(function() {
|
||||
var selected = $(this).val();
|
||||
if (selected == 1) {
|
||||
@@ -185,6 +174,21 @@
|
||||
changeNotify();
|
||||
});
|
||||
|
||||
function changeCommandPlaceholder() {
|
||||
var selectedId = $('#protocol').val();
|
||||
switch (selectedId) {
|
||||
case '1':
|
||||
$('#command').attr('placeholder', '请输入URL地址');
|
||||
break;
|
||||
case '2':
|
||||
$('#command').attr('placeholder', '请输入shell命令');
|
||||
break;
|
||||
case '3':
|
||||
$('#command').attr('placeholder', '请输入系统命令');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function showNotify() {
|
||||
var notifyStatus = {{{.Task.NotifyStatus}}};
|
||||
if (notifyStatus > 0) {
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env bash
|
||||
# set -x -u
|
||||
# 上传二进制包到七牛
|
||||
|
||||
if [[ -z $QINIU_ACCESS_KEY || -z $QINIU_SECRET_KEY || -z $QINIU_URL ]];then
|
||||
echo 'QINIU_ACCESS_KEY | QINIU_SECRET_KEY | QINIU_URL is need'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 打包
|
||||
for i in linux darwin windows
|
||||
do
|
||||
./build.sh -p $i
|
||||
if [[ ! $? ]];then
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# 身份认证
|
||||
qrsctl login $QINIU_ACCESS_KEY $QINIU_SECRET_KEY
|
||||
|
||||
# 上传
|
||||
for i in `ls gocron*.gz gocron*.zip`
|
||||
do
|
||||
# 上传文件 qrsctl put bucket key srcFile
|
||||
KEY=gocron/$i
|
||||
qrsctl put github $KEY $i
|
||||
if [[ ! $? ]];then
|
||||
break
|
||||
fi
|
||||
echo "刷新七牛CDN-" $QINIU_URL/$KEY
|
||||
qrsctl cdn/refresh $QINIU_URL/$KEY
|
||||
rm $i
|
||||
done
|
||||
|
||||
echo '打包并上传成功'
|
||||
Reference in New Issue
Block a user