gitee.com/sasukebo/go-micro/v4@v4.7.1/service.go (about)

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