move web server to goroutine
This commit is contained in:
parent
2f1267016d
commit
d7ea0508cf
47
cmd/root.go
47
cmd/root.go
@ -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())
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user