From 1577456cb6f20e8c06b7425e325da560f4c6c950 Mon Sep 17 00:00:00 2001 From: Jay Date: Wed, 7 Jul 2021 23:51:10 +0800 Subject: [PATCH] [feat] add cron type job --- cmd/svc/main.go | 107 ++++++++++++++++++++++++++++++++++++++++--- go.mod | 2 +- pkg/server/server.go | 2 +- 3 files changed, 103 insertions(+), 8 deletions(-) diff --git a/cmd/svc/main.go b/cmd/svc/main.go index 88a9ff6..b1379a6 100644 --- a/cmd/svc/main.go +++ b/cmd/svc/main.go @@ -1,20 +1,24 @@ package main import ( + "bufio" "context" "deploy/pkg/config" "deploy/pkg/logger" "deploy/pkg/server" "deploy/pkg/tools" + "errors" "flag" "fmt" "log" "net/http" "os" + "os/exec" "os/signal" "syscall" "time" + "github.com/robfig/cron/v3" "github.com/sirupsen/logrus" "gopkg.in/fsnotify.v1" ) @@ -81,11 +85,20 @@ func runService(reload <-chan struct{}) { log := logger.NewLogger(nil) var svc *http.Server + var cron *Cron // infinity loop for { + cfg, err := config.Load(cfgPath) + if err != nil { + log.Fatal(err) + } + if svc == nil { - svc = startServer(log) + svc = startServer(cfg, log) + } + if cron == nil { + cron = startCron(cfg, log) } select { @@ -94,8 +107,11 @@ func runService(reload <-chan struct{}) { // channel closed exit program if err := stopServer(svc); err != nil { log.Fatal(err) - return } + if err := stopCron(cron); err != nil { + log.Fatal(err) + } + return } if time.Since(lastReload).Seconds() < float64(2*time.Second) { break @@ -105,17 +121,96 @@ func runService(reload <-chan struct{}) { if err := stopServer(svc); err != nil { log.Fatal(err) } + if err := stopCron(cron); err != nil { + log.Fatal(err) + } svc = nil + cron = nil } } } -func startServer(log *logrus.Logger) *http.Server { - cfg, err := config.Load(cfgPath) - if err != nil { - log.Fatal(err) +type Cron struct { + *cron.Cron + Logger *logrus.Logger +} + +func (c *Cron) setJobs(cfg *config.Config) { + for _, v := range cfg.CronJobs { + c.AddFunc(v.CronTime, func() { + cmd := exec.Command(v.Script) + + // r, w := io.Pipe() + nlog := c.Logger.WithFields(logrus.Fields{"module": "cron", "script": v.Script}) + reader, err := cmd.StdoutPipe() + if err != nil { + nlog.Warnf("setup pipe out fail: %+v\n", err) + } + errReader, err := cmd.StderrPipe() + if err != nil { + nlog.Warnf("setup pipe out fail: %+v\n", err) + } + + if err := cmd.Start(); err != nil { + nlog.Warnf("start script fail: %+v\n", err) + } + + go func() { + in := bufio.NewScanner(reader) + for in.Scan() { + nlog.Debugf(in.Text()) + } + if err := in.Err(); err != nil { + nlog.Warnf("script error: %+v\n", err) + } + }() + go func() { + in := bufio.NewScanner(errReader) + for in.Scan() { + nlog.Debugf(in.Text()) + } + if err := in.Err(); err != nil { + nlog.Warnf("script error: %+v\n", err) + } + }() + + }) } +} + +func startCron(cfg *config.Config, log *logrus.Logger) *Cron { + tz, err := time.LoadLocation("Asia/Taipei") + if err != nil { + panic(err) + } + c := cron.New( + cron.WithLocation(tz), + cron.WithParser(cron.NewParser(cron.Minute|cron.Hour|cron.Dom|cron.Month|cron.Dow)), + ) + + c2 := &Cron{Cron: c, Logger: log} + + c2.setJobs(cfg) + c2.Start() + + return c2 +} + +func stopCron(c *Cron) error { + ctx := c.Stop() + + select { + case <-ctx.Done(): + return nil + case <-time.Tick(time.Second * 5): + // skip stop jobs + return errors.New("stop jobs fail") + } +} + +func startServer(cfg *config.Config, log *logrus.Logger) *http.Server { + engine := server.NewServer(log) // set routes if err := engine.SetRoutes(cfg.Listens); err != nil { diff --git a/go.mod b/go.mod index 0bb4798..8afd494 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module deploy -go 1.17 +go 1.16 require ( github.com/gin-gonic/gin v1.7.2 diff --git a/pkg/server/server.go b/pkg/server/server.go index 3e22cfc..6be0d7b 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -47,7 +47,7 @@ func (s *HTTPServer) setHandler(check map[string]string, script string) gin.Hand cmd := exec.Command(script) // r, w := io.Pipe() - nlog := s.Logger.WithFields(logrus.Fields{"script": script}) + nlog := s.Logger.WithFields(logrus.Fields{"module": "http", "script": script}) reader, err := cmd.StdoutPipe() if err != nil { nlog.Warnf("setup pipe out fail: %+v\n", err)