isle/go/cmd/entrypoint/daemon.go

99 lines
2.5 KiB
Go

package main
import (
"context"
"fmt"
"os"
"isle/daemon"
"dev.mediocregopher.com/mediocre-go-lib.git/mlog"
)
var subCmdDaemon = subCmd{
name: "daemon",
descr: "Runs the isle daemon (Default if no sub-command given)",
do: func(subCmdCtx subCmdCtx) error {
flags := subCmdCtx.flagSet(false)
daemonConfigPath := flags.StringP(
"config-path", "c", "",
"Optional path to a daemon.yml file to load configuration from.",
)
dumpConfig := flags.Bool(
"dump-config", false,
"Write the default configuration file to stdout and exit.",
)
logLevelStr := flags.StringP(
"log-level", "l", "info",
`Maximum log level which should be output. Values can be "debug", "info", "warn", "error", "fatal". Does not apply to sub-processes`,
)
if err := flags.Parse(subCmdCtx.args); err != nil {
return fmt.Errorf("parsing flags: %w", err)
}
ctx := subCmdCtx.ctx
if *dumpConfig {
return daemon.CopyDefaultConfig(os.Stdout, envAppDirPath)
}
logLevel := mlog.LevelFromString(*logLevelStr)
if logLevel == nil {
return fmt.Errorf("couldn't parse log level %q", *logLevelStr)
}
logger := subCmdCtx.logger.WithMaxLevel(logLevel.Int())
runtimeDirCleanup, err := setupAndLockRuntimeDir(ctx, logger)
if err != nil {
return fmt.Errorf("setting up runtime directory: %w", err)
}
defer runtimeDirCleanup()
daemonConfig, err := daemon.LoadConfig(envAppDirPath, *daemonConfigPath)
if err != nil {
return fmt.Errorf("loading daemon config: %w", err)
}
daemonInst, err := daemon.NewDaemon(
logger, daemonConfig, envBinDirPath, nil,
)
if err != nil {
return fmt.Errorf("starting daemon: %w", err)
}
defer func() {
logger.Info(ctx, "Stopping child processes")
if err := daemonInst.Shutdown(); err != nil {
logger.Error(ctx, "Shutting down daemon cleanly failed, there may be orphaned child processes", err)
}
logger.Info(ctx, "Child processes successfully stopped")
}()
{
logger := logger.WithNamespace("http")
httpSrv, err := newHTTPServer(
ctx, logger, daemon.NewRPC(daemonInst),
)
if err != nil {
return fmt.Errorf("starting HTTP server: %w", err)
}
defer func() {
// see comment in daemonInst shutdown logic regarding background
// context.
logger.Info(ctx, "Shutting down HTTP socket")
if err := httpSrv.Shutdown(context.Background()); err != nil {
logger.Error(ctx, "Failed to cleanly shutdown http server", err)
}
}()
}
<-ctx.Done()
return nil
},
}