127 lines
2.9 KiB
Go
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)
|
|
}
|
|
}
|