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
import (
"context"
"fmt"
"log"
"log/slog"
"math/rand"
"os"
"strings"
"time"
"os/signal"
"syscall"
"git.bloy.org/mike/hasshelper/web"
"github.com/spf13/cobra"
@ -22,30 +22,32 @@ var rootCmd = &cobra.Command{
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) {
logLevel := logLevelVar(viper.GetString("loglevel"))
var logLevel slog.Level
logLevel.UnmarshalText([]byte(viper.GetString("loglevel")))
logger := slog.New(slog.NewTextHandler(os.Stdout,
&slog.HandlerOptions{Level: logLevel}))
logger.Info("HASSHelper startup", "version", viper.GetString("version"))
exitchan := make(chan bool)
web.Run(logger, exitchan)
<-exitchan // run the main command until one of the goroutines is done
signalchan := make(chan os.Signal, 1)
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
@ -100,5 +102,4 @@ func initConfig() {
os.Exit(1)
}
}
rand.Seed(time.Now().UnixNano())
}

View File

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