From 8a528e2b4e180c6d74c28dbc529496f1eb5c7c04 Mon Sep 17 00:00:00 2001 From: Sasha Koshka Date: Wed, 31 May 2023 18:08:29 -0400 Subject: [PATCH] Services can now write to pidfiles --- cmd/router/main.go | 24 +++++++++++++++-------- cmd/router/srvhnakra/hnakra.go | 4 ++-- cmd/router/srvhttps/https.go | 4 ++-- service/service.go | 35 ++++++++++++++++++++++------------ 4 files changed, 43 insertions(+), 24 deletions(-) diff --git a/cmd/router/main.go b/cmd/router/main.go index 5138a52..34d73c5 100644 --- a/cmd/router/main.go +++ b/cmd/router/main.go @@ -4,8 +4,9 @@ import "io" import "os" import "log" import "time" -import "hnakra/rotate" import "hnakra/router" +import "hnakra/rotate" +import "hnakra/daemon" import "hnakra/routines" import "hnakra/router/rcon" import "hnakra/router/config" @@ -59,10 +60,10 @@ func main () { manager := routines.Manager { RestartDeadline: time.Second * 8 } rout := router.New(conf) srvhnakra := &srvhnakra.Server { Config: conf, Router: rout } - manager.Append(srvhnakra.ListenAndServe) + manager.Append(srvhnakra) if conf.HTTPSEnable() { srvhttps := &srvhttps.Server { Config: conf, Handler: rout } - manager.Append(srvhttps.ListenAndServe) + manager.Append(srvhttps) } // set up rcon @@ -74,12 +75,19 @@ func main () { log.SetOutput(originalWriter) } + // be a daemon + daemon.ShutdownOnSigint() + pidfile := daemon.PidFile(os.Getenv("HNAKRA_PIDFILE")) + if !pidfile.Empty() { + err := pidfile.Start() + if err != nil { log.Println("!!! could not write pid:", err) } + } + defer func () { + err := pidfile.Close() + if err != nil { log.Println("!!! could not delete pidfile:", err) } + } () + // run servers err = manager.Run() if err != nil { log.Println("XXX", err) } } - -func httpsRoutine (server *srvhttps.Server) { - err := server.ListenAndServe() - if err != nil { log.Println("XXX", err) } -} diff --git a/cmd/router/srvhnakra/hnakra.go b/cmd/router/srvhnakra/hnakra.go index 39a8113..71bbde4 100644 --- a/cmd/router/srvhnakra/hnakra.go +++ b/cmd/router/srvhnakra/hnakra.go @@ -13,7 +13,7 @@ type Server struct { Router *router.Router } -func (server *Server) ListenAndServe () (err error) { +func (server *Server) Run () (err error) { server.underlying, err = tls.Listen ( "tcp", fmt.Sprint(":", server.Config.RouterPort()), config.TLSConfigFor(server.Config)) @@ -29,6 +29,6 @@ func (server *Server) ListenAndServe () (err error) { } } -func (server *Server) Close () error { +func (server *Server) Shutdown () error { return server.underlying.Close() } diff --git a/cmd/router/srvhttps/https.go b/cmd/router/srvhttps/https.go index b90db26..9539d72 100644 --- a/cmd/router/srvhttps/https.go +++ b/cmd/router/srvhttps/https.go @@ -11,7 +11,7 @@ type Server struct { Handler http.Handler } -func (server *Server) ListenAndServe () error { +func (server *Server) Run () error { server.underlying = &http.Server { Addr: fmt.Sprint(":", server.Config.HTTPSPort()), // ReadHeaderTimeout: timeoutReadHeader * time.Second, @@ -26,6 +26,6 @@ func (server *Server) ListenAndServe () error { return server.underlying.ListenAndServeTLS("", "") } -func (server *Server) Close () error { +func (server *Server) Shutdown () error { return server.underlying.Close() } diff --git a/service/service.go b/service/service.go index ada29a2..32da8e2 100644 --- a/service/service.go +++ b/service/service.go @@ -5,6 +5,7 @@ import "os" import "log" import "time" import "hnakra/rotate" +import "hnakra/daemon" import "hnakra/routines" // Service is capable of managing multiple mounts. It also sets up logging @@ -12,6 +13,8 @@ import "hnakra/routines" type Service struct { ServiceInfo Mounts []Mount + + manager routines.Manager } // NewService provides a shorthand for creating a new service, leaving most @@ -29,6 +32,8 @@ func NewService (name, description string, mounts ...Mount) *Service { // Run runs the mounts within the service, and only exits when all of them have // exited. It will automatically start logging to the directory specified by // $HNAKRA_LOG_DIR. If that variable is unset, it will just log to stdout. +// Additionally, if $HNAKRA_PIDFILE is set, it will write the process PID to the +// file specified by it. func (service *Service) Run () error { // set up logging logDir := os.Getenv("HNAKRA_LOG_DIR") @@ -41,16 +46,28 @@ func (service *Service) Run () error { log.Println("... starting service", service.Name) // set up routine manager - manager := routines.Manager { RestartDeadline: time.Second * 8 } - manager.Routines = make([]routines.Routine, len(service.Mounts)) + service.manager = routines.Manager { RestartDeadline: time.Second * 8 } + service.manager.Routines = make([]routines.Routine, len(service.Mounts)) for index, mount := range service.Mounts { - manager.Routines[index] = func () error { + service.manager.Routines[index] = routines.From (func () error { return mount.Run(service.ServiceInfo) - } + }, mount.Shutdown) + } + + // be a daemon + daemon.ShutdownOnSigint(service) + pidfile := daemon.PidFile(os.Getenv("HNAKRA_PIDFILE")) + if !pidfile.Empty() { + err := pidfile.Start() + if err != nil { log.Println("!!! could not write pid:", err) } + defer func () { + err := pidfile.Close() + if err != nil { log.Println("!!! could not delete pidfile:", err) } + } () } // send it - err := manager.Run() + err := service.manager.Run() if err != nil { log.Println("XXX", err) } return err } @@ -70,11 +87,5 @@ func (service *Service) Close () (err error) { // Shutdown gracefully shuts down each mount in the service. This will cause // Run() to exit. func (service *Service) Shutdown () (err error) { - for _, mount := range service.Mounts { - singleErr := mount.Shutdown() - if singleErr != nil { - err = singleErr - } - } - return + return service.manager.Shutdown() }