From a27dfd4b25ecbe926325e32fb08eeba05eb940cf Mon Sep 17 00:00:00 2001 From: nxshock Date: Sun, 23 Oct 2022 10:23:35 +0500 Subject: [PATCH] Add basic Windows service support --- consts.go | 2 ++ go.mod | 1 + go.sum | 3 +++ httpserver.go | 17 ++++++++------- kernel.go | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++ main.go | 47 +++++++++++++++--------------------------- 6 files changed, 88 insertions(+), 39 deletions(-) create mode 100644 kernel.go diff --git a/consts.go b/consts.go index cbc1aa4..fe248bc 100644 --- a/consts.go +++ b/consts.go @@ -1,6 +1,8 @@ package main const ( + programName = "gron" + defaultConfigFileName = "gron.conf" defaultOnSuccessMessageFmt = "Job {{.JobName}} finished." diff --git a/go.mod b/go.mod index 43c462b..57dd24f 100644 --- a/go.mod +++ b/go.mod @@ -22,6 +22,7 @@ require ( github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect github.com/golang-sql/sqlexp v0.1.0 // indirect github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 // indirect + github.com/kardianos/service v1.2.2 github.com/kr/pretty v0.3.0 // indirect github.com/lib/pq v1.10.6 // indirect github.com/pkg/errors v0.9.1 // indirect diff --git a/go.sum b/go.sum index ef5b168..8694b4a 100644 --- a/go.sum +++ b/go.sum @@ -27,6 +27,8 @@ github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 h1:vr3AYkKovP8uR8AvSGGU github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= github.com/jackc/pgx v3.6.2+incompatible h1:2zP5OD7kiyR3xzRYMhOcXVvkDZsImVXfj+yIyTQf3/o= github.com/jackc/pgx v3.6.2+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= +github.com/kardianos/service v1.2.2 h1:ZvePhAHfvo0A7Mftk/tEzqEZ7Q4lgnR8sGz4xu1YX60= +github.com/kardianos/service v1.2.2/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= @@ -71,6 +73,7 @@ golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/httpserver.go b/httpserver.go index 878191e..fb2fbf7 100644 --- a/httpserver.go +++ b/httpserver.go @@ -7,7 +7,6 @@ import ( "io/fs" "net" "net/http" - "os" "sort" "time" @@ -40,7 +39,7 @@ func handler(w http.ResponseWriter, r *http.Request) { globalMutex.RLock() buf := new(bytes.Buffer) - jobEntries := c.Entries() + jobEntries := kernel.c.Entries() jobs := make(map[string][]*Job) for _, jobEntry := range jobEntries { @@ -81,7 +80,7 @@ func handleForceStart(w http.ResponseWriter, r *http.Request) { return } - jobEntries := c.Entries() + jobEntries := kernel.c.Entries() for _, jobEntry := range jobEntries { job := jobEntry.Job.(*Job) @@ -108,7 +107,7 @@ func handleShutdown(w http.ResponseWriter, r *http.Request) { go func() { time.Sleep(time.Second) log.WithField("job", "http_server").Infoln("Shutdown requested") - os.Exit(0) + _ = kernel.Stop(nil) }() } @@ -116,10 +115,10 @@ func handleReloadJobs(w http.ResponseWriter, r *http.Request) { globalMutex.Lock() defer globalMutex.Unlock() - c.Stop() + kernel.c.Stop() - for _, entry := range c.Entries() { - c.Remove(entry.ID) + for _, entry := range kernel.c.Entries() { + kernel.c.Remove(entry.ID) } err := initJobs() @@ -128,7 +127,7 @@ func handleReloadJobs(w http.ResponseWriter, r *http.Request) { return } - c.Start() + kernel.c.Start() http.Redirect(w, r, "/", http.StatusTemporaryRedirect) } @@ -140,7 +139,7 @@ func handleDetails(w http.ResponseWriter, r *http.Request) { return } - jobEntries := c.Entries() + jobEntries := kernel.c.Entries() for _, jobEntry := range jobEntries { job := jobEntry.Job.(*Job) diff --git a/kernel.go b/kernel.go new file mode 100644 index 0000000..b72e056 --- /dev/null +++ b/kernel.go @@ -0,0 +1,57 @@ +package main + +import ( + "github.com/kardianos/service" + "github.com/robfig/cron/v3" + log "github.com/sirupsen/logrus" +) + +type Kernel struct { + // windows service data + svcConfig *service.Config + + // Other data + c *cron.Cron +} + +func NewKernel() *Kernel { + svcConfig := &service.Config{ + Name: "gron", + DisplayName: "Gron Job Scheduler", + Description: "Gron Job Scheduler.", + } + + kernel = &Kernel{ + svcConfig: svcConfig, + c: cron.New()} + + return kernel +} + +func (k *Kernel) Start(s service.Service) error { + go func() { + log.WithField("job", "core").Info("Started.") + + err := initJobs() + if err != nil { + log.Fatalln(err) + } + + kernel.c.Start() + }() + + return nil +} + +func (k *Kernel) Stop(s service.Service) error { + log.Info("Got stop signal.") + + err := mainLogFile.Close() + if err != nil { + log.Fatal(err) + } + + return nil +} + +var kernel *Kernel diff --git a/main.go b/main.go index 1cadfd4..4d55ea7 100644 --- a/main.go +++ b/main.go @@ -3,17 +3,13 @@ package main import ( "io" "os" - "os/signal" "path/filepath" - "syscall" formatter "github.com/antonfisher/nested-logrus-formatter" - "github.com/robfig/cron/v3" + "github.com/kardianos/service" log "github.com/sirupsen/logrus" ) -var c *cron.Cron - func init() { err := initConfig() if err != nil { @@ -36,16 +32,12 @@ func init() { NoColors: true, TrimMessages: true}) - multiWriter := io.MultiWriter(os.Stderr, mainLogFile) - log.SetOutput(multiWriter) - + log.SetOutput(io.MultiWriter(os.Stderr, mainLogFile)) log.SetLevel(log.InfoLevel) initTemplate() go httpServer(config.HttpListenAddr) - - c = cron.New() } func initJobs() error { @@ -66,7 +58,7 @@ func initJobs() error { return err } - _, err = c.AddJob(job.JobConfig.Cron, job) + _, err = kernel.c.AddJob(job.JobConfig.Cron, job) if err != nil { return err } @@ -78,35 +70,30 @@ func initJobs() error { return err } - if len(c.Entries()) == 0 { + if len(kernel.c.Entries()) == 0 { log.Warn("No jobs loaded.") } else { - log.Infof("Loaded jobs count: %d", len(c.Entries())) + log.Infof("Loaded jobs count: %d", len(kernel.c.Entries())) } return nil } func main() { - log := log.WithField("job", "core") + kernel = NewKernel() - log.Info("Started.") - - err := initJobs() - if err != nil { - log.Fatalln(err) - } - - c.Start() - - intChan := make(chan os.Signal) - signal.Notify(intChan, syscall.SIGTERM) - <-intChan - - log.Info("Got stop signal.") - - err = mainLogFile.Close() + s, err := service.New(kernel, kernel.svcConfig) if err != nil { log.Fatal(err) } + + logger, err := s.Logger(nil) + if err != nil { + log.Fatal(err) + } + + err = s.Run() + if err != nil { + logger.Error(err) + } }