From 7e010d0aca6f7ecbebf8719009ce22276a93a8c4 Mon Sep 17 00:00:00 2001 From: ouqiang Date: Wed, 21 Jun 2017 20:19:59 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E5=AE=9A=E6=97=B6?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E5=BC=80=E5=90=AF=E3=80=81=E5=85=B3=E9=97=AD?= =?UTF-8?q?API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .travis.yml | 6 +- gocron-node.go | 4 +- modules/rpc/server/server.go | 5 + routers/routers.go | 2 + templates/task/task_form.html | 9 +- vendor/github.com/ouqiang/timewheel/LICENSE | 21 --- vendor/github.com/ouqiang/timewheel/README.md | 40 ------ .../github.com/ouqiang/timewheel/timewheel.go | 126 ------------------ .../ouqiang/timewheel/timewheel.jpg | Bin 12422 -> 0 bytes vendor/vendor.json | 6 - 10 files changed, 17 insertions(+), 202 deletions(-) delete mode 100644 vendor/github.com/ouqiang/timewheel/LICENSE delete mode 100644 vendor/github.com/ouqiang/timewheel/README.md delete mode 100644 vendor/github.com/ouqiang/timewheel/timewheel.go delete mode 100644 vendor/github.com/ouqiang/timewheel/timewheel.jpg diff --git a/.travis.yml b/.travis.yml index 9b51318..318b66a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,8 @@ language: go go: - 1.7.x -script: go test `go list ./... | grep -v vendor` \ No newline at end of file +script: go test `go list ./... | grep -v vendor` + +notifications: + on_success: never + on_failure: always \ No newline at end of file diff --git a/gocron-node.go b/gocron-node.go index e074560..5096cad 100644 --- a/gocron-node.go +++ b/gocron-node.go @@ -15,5 +15,7 @@ func main() { } else { addr = os.Args[1] } - server.Start(addr) + for { + server.Start(addr) + } } \ No newline at end of file diff --git a/modules/rpc/server/server.go b/modules/rpc/server/server.go index 5980d10..7db666c 100644 --- a/modules/rpc/server/server.go +++ b/modules/rpc/server/server.go @@ -30,6 +30,11 @@ func (s Server) Run(ctx context.Context, req *pb.TaskRequest) (*pb.TaskResponse, } func Start(addr string) { + defer func() { + if err := recover(); err != nil { + grpclog.Println("panic", err) + } + } () l, err := net.Listen("tcp", addr) if err != nil { grpclog.Fatal(err) diff --git a/routers/routers.go b/routers/routers.go index 1bb7d43..17f8fb5 100644 --- a/routers/routers.go +++ b/routers/routers.go @@ -92,6 +92,8 @@ func Register(m *macaron.Macaron) { // API m.Group("/api/v1", func() { m.Post("/tasklog/remove/:id", tasklog.Remove) + m.Post("/task/enable/:id", task.Enable) + m.Post("/task/disable/:id", task.Disable) }, apiAuth); // 404错误 diff --git a/templates/task/task_form.html b/templates/task/task_form.html index 7651bfb..02e1654 100644 --- a/templates/task/task_form.html +++ b/templates/task/task_form.html @@ -53,8 +53,6 @@ - -
-
+
-
-
-
-
+
diff --git a/vendor/github.com/ouqiang/timewheel/LICENSE b/vendor/github.com/ouqiang/timewheel/LICENSE deleted file mode 100644 index 2316abe..0000000 --- a/vendor/github.com/ouqiang/timewheel/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -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. diff --git a/vendor/github.com/ouqiang/timewheel/README.md b/vendor/github.com/ouqiang/timewheel/README.md deleted file mode 100644 index 2e03c0b..0000000 --- a/vendor/github.com/ouqiang/timewheel/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# timewheel -Golang实现的时间轮 - - -![时间轮](https://raw.githubusercontent.com/ouqiang/timewheel/master/timewheel.jpg) - -# 安装 - -```shell -go get -u github.com/ouqiang/timewheel -``` - -# 使用 - -```go -package main - -import ( - "github.com/ouqiang/timewheel" - "time" -) - -func main() { - // tick刻度为1秒, 3600个槽 - tw := timewheel.New(1 * time.Second, 3600) - tw.Start() - tw.Add(5 * time.Second, func() { - // do something - }) - tw.Add(10 * time.Minute, func() { - // do something - }) - tw.Add(35 * time.Hour, func() { - // do something - }) - // 停止 - tw.Stop() -} -``` - diff --git a/vendor/github.com/ouqiang/timewheel/timewheel.go b/vendor/github.com/ouqiang/timewheel/timewheel.go deleted file mode 100644 index f2fea55..0000000 --- a/vendor/github.com/ouqiang/timewheel/timewheel.go +++ /dev/null @@ -1,126 +0,0 @@ -package timewheel - -import ( - "time" - "container/list" -) - -// @author qiang.ou - -type Job func([]interface{}) - -type TimeWheel struct { - interval time.Duration - ticker *time.Ticker - slots []*list.List - currentPos int - slotNum int - job Job - taskChannel chan Task - stopChannel chan bool -} - - -type Task struct { - delay time.Duration - circle int - data []interface{} -} - -func New(interval time.Duration, slotNum int, job Job) *TimeWheel { - if interval <= 0 || slotNum <= 0 || job == nil { - return nil - } - tw := &TimeWheel{ - interval: interval, - slots: make([]*list.List, slotNum), - currentPos: 0, - job: job, - slotNum: slotNum, - taskChannel: make(chan Task), - stopChannel: make(chan bool), - } - - tw.initSlots() - - return tw -} - -func (tw *TimeWheel) initSlots() { - for i := 0; i < tw.slotNum; i++ { - tw.slots[i] = list.New() - } -} - -func (tw *TimeWheel) Start() { - tw.ticker = time.NewTicker(tw.interval) - go tw.start() -} - -func (tw *TimeWheel) Add(delay time.Duration, data []interface{}) { - if delay <= 0 { - return - } - tw.taskChannel <- Task{delay:delay, data: data} -} - -func (tw *TimeWheel) Stop() { - tw.stopChannel <- true -} - -func (tw *TimeWheel) start() { - for { - select { - case <- tw.ticker.C: - tw.tickHandler() - case task := <- tw.taskChannel: - tw.addTask(&task) - case <- tw.stopChannel: - tw.ticker.Stop() - return - } - } -} - -func (tw *TimeWheel) tickHandler() { - l := tw.slots[tw.currentPos] - tw.scanAndRunTask(l) - if tw.currentPos == tw.slotNum - 1 { - tw.currentPos = 0 - } else { - tw.currentPos++ - } -} - -func (tw *TimeWheel) scanAndRunTask(l *list.List) { - for e := l.Front(); e != nil; { - task := e.Value.(*Task) - if task.circle > 0 { - task.circle-- - e = e.Next() - continue - } - - go tw.job(task.data) - next := e.Next() - l.Remove(e) - e = next - } -} - -func (tw *TimeWheel) addTask(task *Task) { - pos, circle := tw.getPositionAndCircle(task.delay) - task.circle = circle - - tw.slots[pos].PushBack(task) -} - -func (tw *TimeWheel) getPositionAndCircle(d time.Duration) (pos int, circle int) { - delaySeconds := int(d.Seconds()) - intervalSeconds := int(tw.interval.Seconds()) - circle = int(delaySeconds / intervalSeconds / tw.slotNum) - pos = int(tw.currentPos + delaySeconds / intervalSeconds) % tw.slotNum - - - return -} \ No newline at end of file diff --git a/vendor/github.com/ouqiang/timewheel/timewheel.jpg b/vendor/github.com/ouqiang/timewheel/timewheel.jpg deleted file mode 100644 index 64a27de76f2e90cafbbf774b1a2fc6bc1ab1708c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12422 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 gX=!#{TrP9*6X`q