move web server to goroutine

This commit is contained in:
Mike Bloy 2024-09-15 00:51:18 -05:00
parent 2f1267016d
commit d7ea0508cf
2 changed files with 43 additions and 35 deletions

View File

@ -1,13 +1,13 @@
package cmd package cmd
import ( import (
"context"
"fmt" "fmt"
"log" "log"
"log/slog" "log/slog"
"math/rand"
"os" "os"
"strings" "os/signal"
"time" "syscall"
"git.bloy.org/mike/hasshelper/web" "git.bloy.org/mike/hasshelper/web"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -22,30 +22,32 @@ var rootCmd = &cobra.Command{
Run: rootCmdRun, Run: rootCmdRun,
} }
func logLevelVar(str string) slog.Level {
levelUpper := strings.ToUpper(str)
switch levelUpper {
case "DEBUG":
return slog.LevelDebug
case "INFO":
return slog.LevelInfo
case "WARN":
return slog.LevelWarn
case "ERROR":
return slog.LevelError
default:
return slog.LevelInfo
}
}
func rootCmdRun(cmd *cobra.Command, args []string) { func rootCmdRun(cmd *cobra.Command, args []string) {
logLevel := logLevelVar(viper.GetString("loglevel")) var logLevel slog.Level
logLevel.UnmarshalText([]byte(viper.GetString("loglevel")))
logger := slog.New(slog.NewTextHandler(os.Stdout, logger := slog.New(slog.NewTextHandler(os.Stdout,
&slog.HandlerOptions{Level: logLevel})) &slog.HandlerOptions{Level: logLevel}))
logger.Info("HASSHelper startup", "version", viper.GetString("version")) logger.Info("HASSHelper startup", "version", viper.GetString("version"))
exitchan := make(chan bool) exitchan := make(chan bool)
web.Run(logger, exitchan) signalchan := make(chan os.Signal, 1)
<-exitchan // run the main command until one of the goroutines is done done := make(chan bool)
signal.Notify(signalchan, syscall.SIGINT, syscall.SIGTERM)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
web.Run(logger, exitchan, ctx)
go func() {
select {
case <-signalchan:
logger.Warn("received interrupt. Exiting")
cancel()
done <- true
case <-exitchan:
logger.Error("unexpected exit of component")
cancel()
done <- true
}
}()
<-done
} }
// Execute will kick off cobra's processing of the root command // Execute will kick off cobra's processing of the root command
@ -100,5 +102,4 @@ func initConfig() {
os.Exit(1) os.Exit(1)
} }
} }
rand.Seed(time.Now().UnixNano())
} }

View File

@ -3,10 +3,12 @@ package web
import ( import (
"fmt" "fmt"
"log/slog" "log/slog"
"net"
"net/http" "net/http"
"time" "time"
"github.com/spf13/viper" "github.com/spf13/viper"
"golang.org/x/net/context"
) )
type configObj struct { type configObj struct {
@ -19,7 +21,7 @@ var config = configObj{}
// Run starts up the webserver part of hasshelper. It writes to exitch if // Run starts up the webserver part of hasshelper. It writes to exitch if
// the webserver ends unexpectedly. Config values will be read from viper. // the webserver ends unexpectedly. Config values will be read from viper.
func Run(rootLogger *slog.Logger, exitch chan bool) { func Run(rootLogger *slog.Logger, exitch chan bool, ctx context.Context) {
rootLogger = rootLogger.With("component", "web") rootLogger = rootLogger.With("component", "web")
config.logger = rootLogger config.logger = rootLogger
config.port = viper.GetInt("webserver_port") config.port = viper.GetInt("webserver_port")
@ -30,15 +32,21 @@ func Run(rootLogger *slog.Logger, exitch chan bool) {
var logger = config.logger var logger = config.logger
logger.Info("Webserver startup", "port", config.port, "imageDir", config.imageDir) logger.Info("Webserver startup", "port", config.port, "imageDir", config.imageDir)
go func() {
addr := fmt.Sprintf(":%d", config.port) server := http.Server{
Addr: fmt.Sprintf(":%d", config.port),
if err := http.ListenAndServe(addr, middleware(http.DefaultServeMux)); err != nil { Handler: middleware(http.DefaultServeMux),
logger.Error("Webserver fatal error", "err", err) BaseContext: func(net.Listener) context.Context {
} else { return ctx
logger.Info("Webserver shutting down") },
} }
exitch <- true if err := server.ListenAndServe(); err != nil {
logger.Error("Webserver fatal error", "err", err)
} else {
logger.Info("Webserver shutting down")
}
exitch <- true
}()
} }
func middleware(next http.Handler) http.Handler { func middleware(next http.Handler) http.Handler {
@ -46,8 +54,7 @@ func middleware(next http.Handler) http.Handler {
logger := config.logger. logger := config.logger.
WithGroup("request"). WithGroup("request").
With("method", r.Method, With("method", r.Method,
"url", r.URL, "url", r.URL)
"remote", r.RemoteAddr)
logger.Info("Starting web request") logger.Info("Starting web request")
start := time.Now() start := time.Now()
next.ServeHTTP(w, r) next.ServeHTTP(w, r)