diff --git a/commonctx/README.md b/commonctx/README.md new file mode 100644 index 0000000..6b44b2a --- /dev/null +++ b/commonctx/README.md @@ -0,0 +1,2 @@ +# Common Context +Contain code that will make work with context easier \ No newline at end of file diff --git a/commonctx/logger.go b/commonctx/logger.go new file mode 100644 index 0000000..1454671 --- /dev/null +++ b/commonctx/logger.go @@ -0,0 +1,17 @@ +package commonctx + +import ( + "context" + + "github.com/sirupsen/logrus" +) + +const LoggerKey = "mainLogger" + +func AddMainLogger(ctx context.Context, logger *logrus.Logger) context.Context { + return context.WithValue(ctx, LoggerKey, logger) +} + +func GetLogger(ctx context.Context) *logrus.Logger { + return ctx.Value(LoggerKey).(*logrus.Logger) +} diff --git a/middleware/README.md b/middleware/README.md new file mode 100644 index 0000000..9e66e5f --- /dev/null +++ b/middleware/README.md @@ -0,0 +1,2 @@ +# Middleware Common +Contain http middlewares that are helpful in the creation of a new webserver \ No newline at end of file diff --git a/server/server.go b/server/server.go index dd0c497..e008353 100644 --- a/server/server.go +++ b/server/server.go @@ -25,11 +25,11 @@ func GetListenAddressFromEnvOrFlags() (string, error) { pHost := flag.String("host", host, "Host address to listen to") pPort := flag.String("port", port, "Port to listen to") - if govalidator.IsHost(*pHost) { + if !govalidator.IsHost(*pHost) { return "", fmt.Errorf("provided 'host' is invalid") } - if govalidator.IsPort(*pPort) { + if !govalidator.IsPort(*pPort) { return "", fmt.Errorf("provided 'port' is invalid") } diff --git a/webserver/webserver.go b/webserver/webserver.go new file mode 100644 index 0000000..c689ad6 --- /dev/null +++ b/webserver/webserver.go @@ -0,0 +1,72 @@ +package webserver + +import ( + "context" + "errors" + "fmt" + "net/http" + "os" + "os/signal" + "syscall" + "time" + + "git.dev.m-and-m.ovh/mderasse/gocommon/commonctx" +) + +const defaultTimeout = 90 * time.Second +const defaultShutdownTimeout = 10 * time.Second + +type cleanupFunc func() error + +type ExecuteServerParams struct { + Cleanup cleanupFunc + ShutdownTimeout *time.Duration +} + +func ExecuteServer(ctx context.Context, srv *http.Server, params *ExecuteServerParams) error { + + log := commonctx.GetLogger(ctx) + + if srv == nil { + return fmt.Errorf("missing http.server params") + } + + if srv.ReadTimeout == 0 { + srv.ReadTimeout = defaultTimeout + } + + if srv.WriteTimeout == 0 { + srv.WriteTimeout = defaultTimeout + } + + log.Infof("launching webserver on %s", srv.Addr) + + go func() { + if err := srv.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) { + log.WithError(err).Fatalf("HTTP server error: %v", err) + } + log.Info("Stopped serving new connections.") + }() + + sigChan := make(chan os.Signal, 1) + signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) + <-sigChan + + shutdownCtx, shutdownRelease := context.WithTimeout(ctx, defaultShutdownTimeout) + defer shutdownRelease() + + if err := srv.Shutdown(shutdownCtx); err != nil { + log.WithError(err).Warnf("HTTP shutdown error: %v", err) + } + + if params.Cleanup != nil { + if err := params.Cleanup(); err != nil { + log.WithError(err).Warnf("Impossible to cleanup correctly after shutdown. error : %v", err) + return nil + } + } + + log.Info("Graceful shutdown complete.") + + return nil +}