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  }