From 9ab2d0ae0b18d2cba1a052a1046a42fbb45b7653 Mon Sep 17 00:00:00 2001 From: leo Date: Tue, 2 May 2023 00:04:04 +0200 Subject: [PATCH] go: handle host+port combinations,shutdown better * add log messages telling the user what went wrong if the app fails to start * improve existing log messages * cleanup: close channels when exiting * cleanup: stop listening for signals when exiting --- config.dhall | 6 +++-- config/config.go | 1 + main.go | 3 +-- run.go | 58 +++++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 59 insertions(+), 9 deletions(-) diff --git a/config.dhall b/config.dhall index 6b4c646..2f089ca 100644 --- a/config.dhall +++ b/config.dhall @@ -45,7 +45,8 @@ let _ = let Config = -- | define configuration schema. - { Port : Natural + { Host : Text + , Port : Natural , AppName : Text , LiveMode : Bool , DevelMode : Bool @@ -58,7 +59,8 @@ let defconf -- | TODO: have this reside on the Internet and import it similar to how -- | the Dhall Prelude is imported. : Config - = { Port = 3000 + = { Host = "" + , Port = 3000 , AppName = "pcmt" , LiveMode = False , DevelMode = False diff --git a/config/config.go b/config/config.go index d2d096c..148d1fb 100644 --- a/config/config.go +++ b/config/config.go @@ -6,6 +6,7 @@ import ( ) type Config struct { + Host string Port int AppName string LiveMode bool diff --git a/main.go b/main.go index 20b70bf..5397172 100644 --- a/main.go +++ b/main.go @@ -10,8 +10,7 @@ func main() { err := run() if err != nil { l := slog.New(slog.NewJSONHandler(os.Stderr)) - // log.Fatalln(err) - l.Error("error running app:", err) + l.Error("unrecoverable failure, stopping the app", "error", err) os.Exit(1) } } diff --git a/run.go b/run.go index fedf563..089eab9 100644 --- a/run.go +++ b/run.go @@ -7,6 +7,7 @@ import ( "net/http" "os" "os/signal" + "strconv" "syscall" "time" @@ -49,7 +50,8 @@ along with this program. If not, see .` ) var ( - addr = flag.String("addr", ":3000", "TCP address:port to listen at") + host = flag.String("host", "unset", "host address to listen on") + port = flag.Int("port", 0, "TCP port to listen on") configFlag = flag.String("config", "config.dhall", "Default path of the config file") devel = flag.Bool("devel", false, "Run the application in dev mode, connect to a local browser-sync instance for hot-reloading") license = flag.Bool("license", false, "Print licensing information and exit") @@ -129,11 +131,52 @@ func run() error { // } e := a.E() - go func() { - if err = e.Start(*addr); err != nil && err != http.ErrServerClosed { - log.Info("shutting down the server") + + // channel used to check whether the app had troubles starting up. + started := make(chan error, 1) + + defer close(started) + + go func(ok chan error) { + p := conf.Port + h := conf.Host + + if flagPort := *port; flagPort != 0 && flagPort > 0 && flagPort < 65536 { + p = flagPort } - }() + + if flagHost := *host; flagHost != "unset" { + h = flagHost + } + + address := h + ":" + strconv.Itoa(p) + + if err = e.Start(address); err != nil && err != http.ErrServerClosed { + log.Error("troubles running the server, bailing", "error", err.Error()) + + ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) + + defer func() { + cancel() + started <- err + }() + + log.Info("shutting down the server") + + if err := e.Shutdown(ctx); err != nil { + log.Info("error shutting down", "error", err) + started <- err + + return + } + } + started <- err + }(started) + + err = <-started + if err != nil { + return err + } quit := make(chan os.Signal, 1) @@ -148,6 +191,11 @@ func run() error { defer func() { log.Infof("Interrupt received, gracefully shutting down the server (timeout %s)", shutdownTimeout) cancel() + + signal.Stop(quit) + + close(quit) + log.Info("Bye!") }()