router/cmd/main.go (100 lines of code) (raw):
package cmd
import (
"context"
"errors"
"flag"
"fmt"
"log"
"os"
"os/signal"
"syscall"
"github.com/wundergraph/cosmo/router/core"
"github.com/wundergraph/cosmo/router/internal/versioninfo"
"github.com/wundergraph/cosmo/router/pkg/config"
"github.com/wundergraph/cosmo/router/pkg/logging"
"github.com/wundergraph/cosmo/router/pkg/profile"
"go.uber.org/zap"
)
var (
overrideEnvFlag = flag.String("override-env", os.Getenv("OVERRIDE_ENV"), "Path to .env file to override environment variables")
configPathFlag = flag.String("config", os.Getenv("CONFIG_PATH"), "Path to the router config file e.g. config.yaml")
routerVersion = flag.Bool("version", false, "Prints the version and dependency information")
pprofListenAddr = flag.String("pprof-addr", os.Getenv("PPROF_ADDR"), "Address to listen for pprof requests. e.g. :6060 for localhost:6060")
memProfilePath = flag.String("memprofile", "", "Path to write memory profile. Memory is a snapshot taken at the time the program exits")
cpuProfilePath = flag.String("cpuprofile", "", "Path to write cpu profile. CPU is measured from when the program starts until the program exits")
help = flag.Bool("help", false, "Prints the help message")
)
func Main() {
// Parse flags before calling profile.Start(), since it may add flags
flag.Parse()
if *help {
flag.PrintDefaults()
os.Exit(0)
} else if *routerVersion {
bi := versioninfo.New(core.Version, core.Commit, core.Date)
fmt.Println(bi.String())
os.Exit(0)
}
result, err := config.LoadConfig(*configPathFlag, *overrideEnvFlag)
if err != nil {
log.Fatalf("Could not load config: %s", err)
}
logLevel, err := logging.ZapLogLevelFromString(result.Config.LogLevel)
if err != nil {
log.Fatalf("Could not parse log level: %s", err)
}
logger := logging.New(!result.Config.JSONLog, result.Config.DevelopmentMode, logLevel).
With(
zap.String("service", "@wundergraph/router"),
zap.String("service_version", core.Version),
)
// Start pprof server if address is provided
if *pprofListenAddr != "" {
pprofSvr := profile.NewServer(*pprofListenAddr, logger)
defer pprofSvr.Close()
go pprofSvr.Listen()
}
// Start profiling if flags are set
profiler := profile.Start(logger, *cpuProfilePath, *memProfilePath)
defer profiler.Finish()
// Handling shutdown
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt,
syscall.SIGHUP, // process is detached from terminal
syscall.SIGTERM, // default for kill
syscall.SIGKILL,
syscall.SIGQUIT, // ctrl + \
syscall.SIGINT, // ctrl+c
)
defer stop()
if *configPathFlag != "" {
logger.Info(
"Config file path provided. Values in the config file have higher priority than environment variables",
zap.String("config_file", *configPathFlag),
)
} else if result.DefaultLoaded {
logger.Info("Found default config file. Values in the config file have higher priority than environment variables",
zap.String("config_file", config.DefaultConfigPath),
)
}
// Provide a way to cancel all running components of the router after graceful shutdown
// Don't use the parent context that is canceled by the signal handler
routerCtx, routerCancel := context.WithCancel(context.Background())
defer routerCancel()
router, err := NewRouter(routerCtx, Params{
Config: &result.Config,
Logger: logger,
})
if err != nil {
logger.Fatal("Could not create router", zap.Error(err))
}
if err = router.Start(routerCtx); err != nil {
logger.Fatal("Could not start router", zap.Error(err))
}
<-ctx.Done()
logger.Info("Graceful shutdown of router initiated", zap.String("shutdown_delay", result.Config.ShutdownDelay.String()))
// Enforce a maximum shutdown delay to avoid waiting forever
// Don't use the parent context that is canceled by the signal handler
shutdownCtx, cancel := context.WithTimeout(context.Background(), result.Config.ShutdownDelay)
defer cancel()
if err = router.Shutdown(shutdownCtx); err != nil {
if errors.Is(err, context.DeadlineExceeded) {
logger.Warn("Router shutdown deadline exceeded. Consider increasing the shutdown delay")
}
logger.Fatal("Could not shutdown router gracefully", zap.Error(err))
} else {
logger.Info("Router shutdown successfully")
}
logger.Debug("Router exiting")
}