frostfs-s3-lifecycler/cmd/s3-lifecycler/app.go
Denis Kirillov 4e71fbeba6 [#1] Add basic repository structure
Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
2024-07-02 12:14:51 +03:00

127 lines
2.9 KiB
Go

package main
import (
"context"
"os"
"os/signal"
"syscall"
"git.frostfs.info/TrueCloudLab/frostfs-s3-lifecycler/internal/logs"
"git.frostfs.info/TrueCloudLab/frostfs-s3-lifecycler/internal/metrics"
"github.com/spf13/viper"
"go.uber.org/zap"
)
type (
App struct {
log *zap.Logger
logLevel zap.AtomicLevel
cfg *viper.Viper
done chan struct{}
appServices []*metrics.Service
appMetrics *metrics.AppMetrics
}
)
const (
HealthStatusUndefined int32 = 0
HealthStatusStarting int32 = 1
HealthStatusReady int32 = 2
HealthStatusShuttingDown int32 = 3
)
func newApp(cfg *viper.Viper, log *zap.Logger, level zap.AtomicLevel) *App {
a := &App{
log: log,
logLevel: level,
cfg: cfg,
done: make(chan struct{}),
appMetrics: metrics.NewAppMetrics(),
}
a.appMetrics.SetHealth(HealthStatusStarting)
return a
}
func (a *App) Wait() {
a.log.Info(logs.ApplicationStarted,
zap.String("app_name", "frostfs-s3-lifecycler"),
zap.String("version", Version))
a.appMetrics.SetHealth(HealthStatusReady)
a.appMetrics.SetVersion(Version)
<-a.done
a.log.Info(logs.ApplicationStopped)
}
func (a *App) Serve(ctx context.Context) {
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGHUP)
a.startAppServices()
loop:
for {
select {
case <-ctx.Done():
break loop
case <-sigs:
a.configReload()
}
}
a.log.Info(logs.StoppingApplication)
a.appMetrics.SetHealth(HealthStatusShuttingDown)
a.stopAppServices()
close(a.done)
}
func (a *App) configReload() {
a.log.Info(logs.SIGHUPConfigReloadStarted)
if !a.cfg.IsSet(cmdConfig) && !a.cfg.IsSet(cmdConfigDir) {
a.log.Warn(logs.FailedToReloadConfigBecauseItsMissed)
return
}
if err := readInConfig(a.cfg); err != nil {
a.log.Warn(logs.FailedToReloadConfig, zap.Error(err))
return
}
if lvl, err := getLogLevel(a.cfg.GetString(cfgLoggerLevel)); err != nil {
a.log.Warn(logs.LogLevelWontBeUpdated, zap.Error(err))
} else {
a.logLevel.SetLevel(lvl)
}
a.stopAppServices()
a.startAppServices()
a.log.Info(logs.SIGHUPConfigReloadCompleted)
}
func (a *App) startAppServices() {
a.appServices = a.appServices[:0]
pprofConfig := metrics.Config{Enabled: a.cfg.GetBool(cfgPprofEnabled), Address: a.cfg.GetString(cfgPprofAddress)}
pprofService := metrics.NewPprofService(a.log, pprofConfig)
a.appServices = append(a.appServices, pprofService)
go pprofService.Start()
prometheusConfig := metrics.Config{Enabled: a.cfg.GetBool(cfgPrometheusEnabled), Address: a.cfg.GetString(cfgPrometheusAddress)}
prometheusService := metrics.NewPrometheusService(a.log, prometheusConfig)
a.appServices = append(a.appServices, prometheusService)
go prometheusService.Start()
}
func (a *App) stopAppServices() {
ctx, cancel := context.WithTimeout(context.Background(), defaultShutdownTimeout)
defer cancel()
for _, svc := range a.appServices {
svc.ShutDown(ctx)
}
}