go-micro.dev/v5@v5.12.0/service/service.go (about) 1 package service 2 3 import ( 4 "os" 5 "os/signal" 6 rtime "runtime" 7 "sync" 8 9 "go-micro.dev/v5/client" 10 "go-micro.dev/v5/cmd" 11 log "go-micro.dev/v5/logger" 12 "go-micro.dev/v5/server" 13 "go-micro.dev/v5/store" 14 signalutil "go-micro.dev/v5/util/signal" 15 ) 16 17 type service struct { 18 opts Options 19 20 once sync.Once 21 } 22 23 func New(opts ...Option) *service { 24 return &service{ 25 opts: newOptions(opts...), 26 } 27 } 28 29 func (s *service) Name() string { 30 return s.opts.Server.Options().Name 31 } 32 33 // Init initializes options. Additionally it calls cmd.Init 34 // which parses command line flags. cmd.Init is only called 35 // on first Init. 36 func (s *service) Init(opts ...Option) { 37 // process options 38 for _, o := range opts { 39 o(&s.opts) 40 } 41 42 s.once.Do(func() { 43 // set cmd name 44 if len(s.opts.Cmd.App().Name) == 0 { 45 s.opts.Cmd.App().Name = s.Server().Options().Name 46 } 47 48 // Initialize the command flags, overriding new service 49 if err := s.opts.Cmd.Init( 50 cmd.Auth(&s.opts.Auth), 51 cmd.Broker(&s.opts.Broker), 52 cmd.Registry(&s.opts.Registry), 53 cmd.Transport(&s.opts.Transport), 54 cmd.Client(&s.opts.Client), 55 cmd.Config(&s.opts.Config), 56 cmd.Server(&s.opts.Server), 57 cmd.Store(&s.opts.Store), 58 cmd.Profile(&s.opts.Profile), 59 ); err != nil { 60 s.opts.Logger.Log(log.FatalLevel, err) 61 } 62 63 // we might not want to do this 64 name := s.opts.Cmd.App().Name 65 err := s.opts.Store.Init(store.Table(name)) 66 if err != nil { 67 s.opts.Logger.Log(log.FatalLevel, err) 68 } 69 }) 70 } 71 72 func (s *service) Options() Options { 73 return s.opts 74 } 75 76 func (s *service) Client() client.Client { 77 return s.opts.Client 78 } 79 80 func (s *service) Server() server.Server { 81 return s.opts.Server 82 } 83 84 func (s *service) String() string { 85 return "micro" 86 } 87 88 func (s *service) Start() error { 89 for _, fn := range s.opts.BeforeStart { 90 if err := fn(); err != nil { 91 return err 92 } 93 } 94 95 if err := s.opts.Server.Start(); err != nil { 96 return err 97 } 98 99 for _, fn := range s.opts.AfterStart { 100 if err := fn(); err != nil { 101 return err 102 } 103 } 104 105 return nil 106 } 107 108 func (s *service) Stop() error { 109 var err error 110 111 for _, fn := range s.opts.BeforeStop { 112 err = fn() 113 } 114 115 if err := s.opts.Server.Stop(); err != nil { 116 return err 117 } 118 119 for _, fn := range s.opts.AfterStop { 120 err = fn() 121 } 122 123 return err 124 } 125 126 func (s *service) Handle(v interface{}) error { 127 return s.opts.Server.Handle( 128 s.opts.Server.NewHandler(v), 129 ) 130 } 131 132 func (s *service) Run() (err error) { 133 logger := s.opts.Logger 134 135 // exit when help flag is provided 136 for _, v := range os.Args[1:] { 137 if v == "-h" || v == "--help" { 138 os.Exit(0) 139 } 140 } 141 142 // start the profiler 143 if s.opts.Profile != nil { 144 // to view mutex contention 145 rtime.SetMutexProfileFraction(5) 146 // to view blocking profile 147 rtime.SetBlockProfileRate(1) 148 149 if err = s.opts.Profile.Start(); err != nil { 150 return err 151 } 152 153 defer func() { 154 if nerr := s.opts.Profile.Stop(); nerr != nil { 155 logger.Log(log.ErrorLevel, nerr) 156 } 157 }() 158 } 159 160 logger.Logf(log.InfoLevel, "Starting [service] %s", s.Name()) 161 162 if err = s.Start(); err != nil { 163 return err 164 } 165 166 ch := make(chan os.Signal, 1) 167 if s.opts.Signal { 168 signal.Notify(ch, signalutil.Shutdown()...) 169 } 170 171 select { 172 // wait on kill signal 173 case <-ch: 174 // wait on context cancel 175 case <-s.opts.Context.Done(): 176 } 177 178 return s.Stop() 179 }