github.com/micro/go-micro/v2@v2.9.1/service.go (about) 1 package micro 2 3 import ( 4 "os" 5 "os/signal" 6 rtime "runtime" 7 "strings" 8 "sync" 9 10 "github.com/micro/go-micro/v2/auth" 11 "github.com/micro/go-micro/v2/client" 12 "github.com/micro/go-micro/v2/config/cmd" 13 "github.com/micro/go-micro/v2/debug/service/handler" 14 "github.com/micro/go-micro/v2/debug/stats" 15 "github.com/micro/go-micro/v2/debug/trace" 16 "github.com/micro/go-micro/v2/logger" 17 "github.com/micro/go-micro/v2/plugin" 18 "github.com/micro/go-micro/v2/server" 19 "github.com/micro/go-micro/v2/store" 20 signalutil "github.com/micro/go-micro/v2/util/signal" 21 "github.com/micro/go-micro/v2/util/wrapper" 22 ) 23 24 type service struct { 25 opts Options 26 27 once sync.Once 28 } 29 30 func newService(opts ...Option) Service { 31 service := new(service) 32 options := newOptions(opts...) 33 34 // service name 35 serviceName := options.Server.Options().Name 36 37 // we pass functions to the wrappers since the values can change during initialisation 38 authFn := func() auth.Auth { return options.Server.Options().Auth } 39 cacheFn := func() *client.Cache { return options.Client.Options().Cache } 40 41 // wrap client to inject From-Service header on any calls 42 options.Client = wrapper.FromService(serviceName, options.Client) 43 options.Client = wrapper.TraceCall(serviceName, trace.DefaultTracer, options.Client) 44 options.Client = wrapper.CacheClient(cacheFn, options.Client) 45 options.Client = wrapper.AuthClient(authFn, options.Client) 46 47 // wrap the server to provide handler stats 48 options.Server.Init( 49 server.WrapHandler(wrapper.HandlerStats(stats.DefaultStats)), 50 server.WrapHandler(wrapper.TraceHandler(trace.DefaultTracer)), 51 server.WrapHandler(wrapper.AuthHandler(authFn)), 52 ) 53 54 // set opts 55 service.opts = options 56 57 return service 58 } 59 60 func (s *service) Name() string { 61 return s.opts.Server.Options().Name 62 } 63 64 // Init initialises options. Additionally it calls cmd.Init 65 // which parses command line flags. cmd.Init is only called 66 // on first Init. 67 func (s *service) Init(opts ...Option) { 68 // process options 69 for _, o := range opts { 70 o(&s.opts) 71 } 72 73 s.once.Do(func() { 74 // setup the plugins 75 for _, p := range strings.Split(os.Getenv("MICRO_PLUGIN"), ",") { 76 if len(p) == 0 { 77 continue 78 } 79 80 // load the plugin 81 c, err := plugin.Load(p) 82 if err != nil { 83 logger.Fatal(err) 84 } 85 86 // initialise the plugin 87 if err := plugin.Init(c); err != nil { 88 logger.Fatal(err) 89 } 90 } 91 92 // set cmd name 93 if len(s.opts.Cmd.App().Name) == 0 { 94 s.opts.Cmd.App().Name = s.Server().Options().Name 95 } 96 97 // Initialise the command flags, overriding new service 98 if err := s.opts.Cmd.Init( 99 cmd.Auth(&s.opts.Auth), 100 cmd.Broker(&s.opts.Broker), 101 cmd.Registry(&s.opts.Registry), 102 cmd.Runtime(&s.opts.Runtime), 103 cmd.Transport(&s.opts.Transport), 104 cmd.Client(&s.opts.Client), 105 cmd.Config(&s.opts.Config), 106 cmd.Server(&s.opts.Server), 107 cmd.Store(&s.opts.Store), 108 cmd.Profile(&s.opts.Profile), 109 ); err != nil { 110 logger.Fatal(err) 111 } 112 113 // Explicitly set the table name to the service name 114 name := s.opts.Cmd.App().Name 115 s.opts.Store.Init(store.Table(name)) 116 }) 117 } 118 119 func (s *service) Options() Options { 120 return s.opts 121 } 122 123 func (s *service) Client() client.Client { 124 return s.opts.Client 125 } 126 127 func (s *service) Server() server.Server { 128 return s.opts.Server 129 } 130 131 func (s *service) String() string { 132 return "micro" 133 } 134 135 func (s *service) Start() error { 136 for _, fn := range s.opts.BeforeStart { 137 if err := fn(); err != nil { 138 return err 139 } 140 } 141 142 if err := s.opts.Server.Start(); err != nil { 143 return err 144 } 145 146 for _, fn := range s.opts.AfterStart { 147 if err := fn(); err != nil { 148 return err 149 } 150 } 151 152 return nil 153 } 154 155 func (s *service) Stop() error { 156 var gerr error 157 158 for _, fn := range s.opts.BeforeStop { 159 if err := fn(); err != nil { 160 gerr = err 161 } 162 } 163 164 if err := s.opts.Server.Stop(); err != nil { 165 return err 166 } 167 168 for _, fn := range s.opts.AfterStop { 169 if err := fn(); err != nil { 170 gerr = err 171 } 172 } 173 174 return gerr 175 } 176 177 func (s *service) Run() error { 178 // register the debug handler 179 s.opts.Server.Handle( 180 s.opts.Server.NewHandler( 181 handler.NewHandler(s.opts.Client), 182 server.InternalHandler(true), 183 ), 184 ) 185 186 // start the profiler 187 if s.opts.Profile != nil { 188 // to view mutex contention 189 rtime.SetMutexProfileFraction(5) 190 // to view blocking profile 191 rtime.SetBlockProfileRate(1) 192 193 if err := s.opts.Profile.Start(); err != nil { 194 return err 195 } 196 defer s.opts.Profile.Stop() 197 } 198 199 if logger.V(logger.InfoLevel, logger.DefaultLogger) { 200 logger.Infof("Starting [service] %s", s.Name()) 201 } 202 203 if err := s.Start(); err != nil { 204 return err 205 } 206 207 ch := make(chan os.Signal, 1) 208 if s.opts.Signal { 209 signal.Notify(ch, signalutil.Shutdown()...) 210 } 211 212 select { 213 // wait on kill signal 214 case <-ch: 215 // wait on context cancel 216 case <-s.opts.Context.Done(): 217 } 218 219 return s.Stop() 220 }