cmd/ctrld: response to OS service manager earlier

When startup, ctrld waits for network up before calling s.Run to starts
its logic. However, if network is down on startup, ctrld will hang on
waiting for network up. That causes OS service manager unhappy, as ctrld
do not response to it, marking ctrld as failure service and never start
ctrld again.

To fix this, we should call s.Run as soon as possible, and use a channel
for waiting a signal that we can actual do our logic after network up.

Update #34
This commit is contained in:
Cuong Manh Le authored and Cuong Manh Le committed 2023-03-31 10:14:46 +07:00
1 parent f0c604a9f1
commit 9927803497
2 files changed
+37 -17

No files matched your search

+31 -16
View File
@@ -90,6 +90,35 @@ func initCLI() {
if daemon && runtime.GOOS == "windows" {
log.Fatal("Cannot run in daemon mode. Please install a Windows service.")
}
waitCh := make(chan struct{})
stopCh := make(chan struct{})
if !daemon {
// We need to call s.Run() as soon as possible to response to the OS manager, so it
// can see ctrld is running and don't mark ctrld as failed service.
go func() {
p := &prog{
waitCh: waitCh,
stopCh: stopCh,
}
s, err := service.New(p, svcConfig)
if err != nil {
mainLog.Fatal().Err(err).Msg("failed create new service")
}
serviceLogger, err := s.Logger(nil)
if err != nil {
mainLog.Error().Err(err).Msg("failed to get service logger")
return
}
if err := s.Run(); err != nil {
if sErr := serviceLogger.Error(err); sErr != nil {
mainLog.Error().Err(sErr).Msg("failed to write service log")
}
mainLog.Error().Err(err).Msg("failed to start service")
}
}()
}
noConfigStart := isNoConfigStart(cmd)
writeDefaultConfig := !noConfigStart && configBase64 == ""
configs := []struct {
@@ -150,22 +179,8 @@ func initCLI() {
os.Exit(0)
}
s, err := service.New(&prog{}, svcConfig)
if err != nil {
mainLog.Fatal().Err(err).Msg("failed create new service")
}
serviceLogger, err := s.Logger(nil)
if err != nil {
mainLog.Error().Err(err).Msg("failed to get service logger")
return
}
if err := s.Run(); err != nil {
if sErr := serviceLogger.Error(err); sErr != nil {
mainLog.Error().Err(sErr).Msg("failed to write service log")
}
mainLog.Error().Err(err).Msg("failed to start service")
}
close(waitCh)
<-stopCh
},
}
runCmd.Flags().BoolVarP(&daemon, "daemon", "d", false, "Run as daemon")
+6 -1
View File
@@ -28,7 +28,9 @@ var svcConfig = &service.Config{
}
type prog struct {
mu sync.Mutex
mu sync.Mutex
waitCh chan struct{}
stopCh chan struct{}
cfg *ctrld.Config
cache dnscache.Cacher
@@ -41,6 +43,8 @@ func (p *prog) Start(s service.Service) error {
}
func (p *prog) run() {
// Wait the caller to signal that we can do our logic.
<-p.waitCh
p.preRun()
if p.cfg.Service.CacheEnable {
cacher, err := dnscache.NewLRUCache(p.cfg.Service.CacheSize)
@@ -132,6 +136,7 @@ func (p *prog) Stop(s service.Service) error {
return err
}
mainLog.Info().Msg("Service stopped")
close(p.stopCh)
return nil
}