package micro import ( "os" "os/signal" "sync" "syscall" "time" log "github.com/micro/go-log" "github.com/micro/go-micro/client" "github.com/micro/go-micro/cmd" "github.com/micro/go-micro/metadata" "github.com/micro/go-micro/server" ) type service struct { opts Options once sync.Once } func newService(opts ...Option) Service { options := newOptions(opts...) options.Client = &clientWrapper{ options.Client, metadata.Metadata{ HeaderPrefix + "From-Service": options.Server.Options().Name, }, } return &service{ opts: options, } } func (s *service) run(exit chan bool) { if s.opts.RegisterInterval <= time.Duration(0) { return } t := time.NewTicker(s.opts.RegisterInterval) for { select { case <-t.C: err := s.opts.Server.Register() if err != nil { log.Log("service run Server.Register error: ", err) } case <-exit: t.Stop() return } } } // Init initialises options. Additionally it calls cmd.Init // which parses command line flags. cmd.Init is only called // on first Init. func (s *service) Init(opts ...Option) { // process options for _, o := range opts { o(&s.opts) } s.once.Do(func() { // Initialise the command flags, overriding new service s.opts.Cmd.Init( cmd.Broker(&s.opts.Broker), cmd.Registry(&s.opts.Registry), cmd.Transport(&s.opts.Transport), cmd.Client(&s.opts.Client), cmd.Server(&s.opts.Server), ) }) } func (s *service) Options() Options { return s.opts } func (s *service) Client() client.Client { return s.opts.Client } func (s *service) Server() server.Server { return s.opts.Server } func (s *service) String() string { return "go-micro" } func (s *service) Start() error { for _, fn := range s.opts.BeforeStart { if err := fn(); err != nil { return err } } if err := s.opts.Server.Start(); err != nil { return err } if err := s.opts.Server.Register(); err != nil { return err } for _, fn := range s.opts.AfterStart { if err := fn(); err != nil { return err } } return nil } func (s *service) Stop() error { var gerr error for _, fn := range s.opts.BeforeStop { if err := fn(); err != nil { gerr = err } } if err := s.opts.Server.Deregister(); err != nil { return err } if err := s.opts.Server.Stop(); err != nil { return err } for _, fn := range s.opts.AfterStop { if err := fn(); err != nil { gerr = err } } return gerr } func (s *service) Run() error { if err := s.Start(); err != nil { return err } // start reg loop ex := make(chan bool) go s.run(ex) ch := make(chan os.Signal, 1) signal.Notify(ch, syscall.SIGTERM, syscall.SIGINT, syscall.SIGKILL) select { // wait on kill signal case <-ch: // wait on context cancel case <-s.opts.Context.Done(): } // exit reg loop close(ex) return s.Stop() }