cv/app/server/main.go
2023-06-02 12:35:51 +02:00

127 lines
2.8 KiB
Go

package main
import (
"fmt"
"net/http"
_ "net/http/pprof"
"os"
"os/signal"
"syscall"
"go.uber.org/zap"
"go.c3c.cz/cv/app/server/internal/config"
"go.c3c.cz/cv/app/server/internal/httpserver"
"go.c3c.cz/cv/app/server/internal/pprofserver"
"go.c3c.cz/cv/app/server/internal/version"
)
func main() {
defer handleExit()
notice := "Starting version "
if version.Tag != "" {
notice += version.Tag
} else {
notice += "latest"
}
if version.Commit != "" {
notice = fmt.Sprintf("%s (%s)", notice, version.Commit)
}
var logger *zap.Logger
var err error
logger, err = config.LoggerConfig.Build()
if err != nil {
fmt.Println(notice)
fmt.Println(version.CommitTime.Format("Committed at 2006/01/02 15:04:05 MST"))
panic(Exit{fmt.Errorf("logger creation failed")})
}
logger.Info(
"App initializing",
zap.String("version", version.Tag),
zap.String("commit", version.Commit),
zap.Time("commitTime", version.CommitTime),
)
defer func() {
_ = logger.Sync()
}()
httpSrv, err := httpserver.New(&httpserver.Options{
BindAddr: config.BindAddrHttp,
FrontendConfig: config.Frontend,
Logger: logger,
})
if err != nil {
logger.Error("HTTP server creation failed", zap.Error(err))
panic(Exit{err})
}
quit := struct {
os chan os.Signal
pprof chan error
http chan error
}{
os: make(chan os.Signal, 1),
pprof: make(chan error, 1),
http: make(chan error, 1),
}
pprofSrv := pprofserver.New(pprofserver.Options{
BindAddr: config.BindAddrPprof,
Logger: logger,
LogLevelHandler: config.LoggerConfig.Level,
})
// Pprof server.
go func() {
logger.Info("debug server was started", zap.String("BindAddr", config.BindAddrPprof))
quit.pprof <- pprofSrv.ListenAndServe()
}()
go func() {
logger.Info("http server was started", zap.String("BindAddr", config.BindAddrHttp))
pprofSrv.SetReady()
err := httpSrv.ListenAndServe()
if err != http.ErrServerClosed {
quit.http <- err
}
}()
logger.Info("application started")
signal.Notify(quit.os, os.Interrupt, syscall.SIGTERM)
select {
case s := <-quit.os:
sig, _ := s.(syscall.Signal)
logger.Info("Signal received\n", zap.Int("signal", int(sig)))
pprofSrv.SetNotReady()
httpSrv.ShutdownWithDelay(config.GraceTerminationDelay, config.GraceTerminationLimit)
case err := <-quit.pprof:
logger.Error("app shutdown was triggered by a pprof server error", zap.Error(err))
httpSrv.ShutdownWithDelay(config.GraceTerminationDelay, config.GraceTerminationLimit)
case err := <-quit.http:
logger.Error("app shutdown was triggered by an http server error", zap.Error(err))
}
}
type Exit struct {
err error
}
func handleExit() {
if e := recover(); e != nil {
if exit, ok := e.(Exit); ok {
fmt.Println(exit.err)
os.Exit(1)
}
panic(e)
}
}