Files
go-alived/internal/cmd/run.go
2025-12-08 22:23:45 +08:00

134 lines
3.4 KiB
Go

package cmd
import (
"os"
"os/signal"
"syscall"
"github.com/loveuer/go-alived/internal/health"
"github.com/loveuer/go-alived/internal/vrrp"
"github.com/loveuer/go-alived/pkg/config"
"github.com/loveuer/go-alived/pkg/logger"
"github.com/spf13/cobra"
)
var (
configFile string
debug bool
)
var runCmd = &cobra.Command{
Use: "run",
Short: "Run the VRRP service",
Long: `Start the go-alived VRRP service with health checking.`,
Run: runService,
}
func init() {
rootCmd.AddCommand(runCmd)
runCmd.Flags().StringVarP(&configFile, "config", "c", "/etc/go-alived/config.yaml", "path to configuration file")
runCmd.Flags().BoolVarP(&debug, "debug", "d", false, "enable debug mode")
}
func runService(cmd *cobra.Command, args []string) {
log := logger.New(debug)
log.Info("starting go-alived...")
log.Info("loading configuration from: %s", configFile)
cfg, err := config.Load(configFile)
if err != nil {
log.Error("failed to load configuration: %v", err)
os.Exit(1)
}
log.Info("configuration loaded successfully")
log.Debug("config: %+v", cfg)
healthMgr, err := health.LoadFromConfig(cfg, log)
if err != nil {
log.Error("failed to load health check configuration: %v", err)
os.Exit(1)
}
vrrpMgr := vrrp.NewManager(log)
if err := vrrpMgr.LoadFromConfig(cfg); err != nil {
log.Error("failed to load VRRP configuration: %v", err)
os.Exit(1)
}
setupHealthTracking(vrrpMgr, healthMgr, log)
healthMgr.StartAll()
if err := vrrpMgr.StartAll(); err != nil {
log.Error("failed to start VRRP instances: %v", err)
os.Exit(1)
}
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)
for {
sig := <-sigChan
switch sig {
case syscall.SIGHUP:
log.Info("received SIGHUP, reloading configuration...")
newCfg, err := config.Load(configFile)
if err != nil {
log.Error("failed to reload configuration: %v", err)
continue
}
if err := vrrpMgr.Reload(newCfg); err != nil {
log.Error("failed to reload VRRP: %v", err)
continue
}
cfg = newCfg
log.Info("configuration reloaded successfully")
case syscall.SIGINT, syscall.SIGTERM:
log.Info("received signal %v, shutting down...", sig)
cleanup(log, vrrpMgr, healthMgr)
os.Exit(0)
}
}
}
func cleanup(log *logger.Logger, vrrpMgr *vrrp.Manager, healthMgr *health.Manager) {
log.Info("cleaning up resources...")
healthMgr.StopAll()
vrrpMgr.StopAll()
}
func setupHealthTracking(vrrpMgr *vrrp.Manager, healthMgr *health.Manager, log *logger.Logger) {
instances := vrrpMgr.GetAllInstances()
for _, inst := range instances {
for _, trackScript := range inst.TrackScripts {
monitor, ok := healthMgr.GetMonitor(trackScript)
if !ok {
log.Warn("[%s] track_script '%s' not found in health checkers", inst.Name, trackScript)
continue
}
instanceName := inst.Name
monitor.OnStateChange(func(checkerName string, oldHealthy, newHealthy bool) {
vrrpInst, ok := vrrpMgr.GetInstance(instanceName)
if !ok {
return
}
if newHealthy && !oldHealthy {
log.Info("[%s] health check '%s' recovered, resetting priority", instanceName, checkerName)
vrrpInst.ResetPriority()
} else if !newHealthy && oldHealthy {
log.Warn("[%s] health check '%s' failed, decreasing priority", instanceName, checkerName)
vrrpInst.AdjustPriority(-10)
}
})
log.Info("[%s] tracking health check: %s", inst.Name, trackScript)
}
}
}