1717package cmd
1818
1919import (
20- "github.com/mimuret/dtap/v2/pkg/config"
20+ "context"
21+ "os"
22+ "os/signal"
23+ "sync"
24+ "syscall"
25+
2126 "github.com/mimuret/dtap/v2/pkg/core"
2227 _ "github.com/mimuret/dtap/v2/pkg/core/plugins"
23- "github.com/mimuret/dtap/v2/pkg/logger "
24- "github.com/spf13/afero "
28+ "github.com/mimuret/dtap/v2/pkg/promauto "
29+ "github.com/prometheus/client_golang/prometheus "
2530 "github.com/spf13/cobra"
2631 "go.uber.org/zap"
2732)
2833
34+ type Runner interface {
35+ Run (context.Context ) error
36+ }
37+
2938var cfgFile string
39+ var runnerCh chan Runner
3040
3141// rootCmd represents the base command when called without any subcommands
3242var rootCmd = & cobra.Command {
@@ -36,25 +46,74 @@ var rootCmd = &cobra.Command{
3646 // Uncomment the following line if your bare application
3747 // has an action associated with it:
3848 RunE : func (cmd * cobra.Command , args []string ) error {
39- c , err := config .LoadConfig (afero .NewOsFs (), cfgFile )
40- if err != nil {
41- return err
42- }
43- l , err := logger .New (c .LogLevel )
49+ var (
50+ reloadCh = make (chan struct {}, 1 )
51+ sigHUP = make (chan os.Signal , 1 )
52+ sigSTOP = make (chan os.Signal , 1 )
53+ wg = & sync.WaitGroup {}
54+ cctx context.Context
55+ cancelFunc context.CancelFunc
56+ )
57+ signal .Notify (sigHUP , syscall .SIGHUP )
58+ signal .Notify (sigSTOP , syscall .SIGINT , syscall .SIGTERM )
59+ defer close (sigHUP )
60+ defer close (sigSTOP )
61+ logger , err := makeRunner (cfgFile , reloadCh )
4462 if err != nil {
4563 return err
4664 }
4765
48- ctl := core .NewController (c , l )
49- if err := ctl .Setup (); err != nil {
50- l .Fatal ("failed to setup" , zap .Error (err ))
66+ LOOP:
67+ for {
68+ select {
69+ case r := <- runnerCh :
70+ wg .Add (1 )
71+ cctx , cancelFunc = context .WithCancel (cmd .Context ())
72+ go func (cctx context.Context ) {
73+ logger .Info ("Start runner." )
74+ if err := r .Run (cctx ); err != nil {
75+ logger .Fatal ("runtime error" , zap .Error (err ))
76+ }
77+ wg .Done ()
78+ }(cctx )
79+ case <- sigSTOP :
80+ logger .Info ("KILL signal recieved." )
81+ cancelFunc ()
82+ wg .Wait ()
83+ break LOOP
84+ case <- sigHUP :
85+ reloadCh <- struct {}{}
86+ case <- reloadCh :
87+ if len (runnerCh ) != 0 {
88+ continue
89+ }
90+ logger .Info ("SIGHUP recieved." )
91+ newLogger , err := makeRunner (cfgFile , reloadCh )
92+ if err != nil {
93+ logger .Error ("failed to reload" , zap .Error (err ))
94+ } else {
95+ logger = newLogger
96+ logger .Info ("Stop the current runner to start reloading." )
97+ cancelFunc ()
98+ wg .Wait ()
99+ }
100+ }
51101 }
52- go ctl .PrometheusListen (cmd .Context ())
53-
54- return ctl .Run (cmd .Context ())
102+ return nil
55103 },
56104}
57105
106+ func makeRunner (cfgFile string , reloadCh chan struct {}) (* zap.Logger , error ) {
107+ registery := prometheus .NewRegistry ()
108+ promauto .Set (registery )
109+ runner , l , err := core .NewRunner (context .Background (), cfgFile , registery , reloadCh )
110+ if err != nil {
111+ return nil , err
112+ }
113+ runnerCh <- runner
114+ return l , nil
115+ }
116+
58117// Execute adds all child commands to the root command and sets flags appropriately.
59118// This is called by main.main(). It only needs to happen once to the rootCmd.
60119func Execute () {
@@ -67,4 +126,5 @@ func init() {
67126 // will be global for your application.
68127
69128 rootCmd .PersistentFlags ().StringVarP (& cfgFile , "config" , "c" , "" , "config file" )
129+ runnerCh = make (chan Runner , 1 )
70130}
0 commit comments