diff --git a/cmd/ctrld/cli.go b/cmd/ctrld/cli.go index d722358..f25cc63 100644 --- a/cmd/ctrld/cli.go +++ b/cmd/ctrld/cli.go @@ -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") diff --git a/cmd/ctrld/prog.go b/cmd/ctrld/prog.go index 6f4abad..0206402 100644 --- a/cmd/ctrld/prog.go +++ b/cmd/ctrld/prog.go @@ -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 }