gitee.com/h79/goutils@v1.22.10/discovery/consul/service.go (about)

     1  /**
     2   * by huqiuyun
     3   * 启动一个服务时,注册到consul中心,从而可以收到配置信息的变化通知
     4   */
     5  package consul
     6  
     7  import (
     8  	"fmt"
     9  	"gitee.com/h79/goutils/common/logger"
    10  	"gitee.com/h79/goutils/common/result"
    11  	"gitee.com/h79/goutils/common/server"
    12  	"gitee.com/h79/goutils/common/system"
    13  	"gitee.com/h79/goutils/discovery/config"
    14  	"gitee.com/h79/goutils/discovery/registry"
    15  	"gitee.com/h79/goutils/discovery/service"
    16  	consul "github.com/hashicorp/consul/api"
    17  	"time"
    18  )
    19  
    20  var _ service.Service = (*clService)(nil)
    21  
    22  type clService struct {
    23  	Base
    24  	id          string
    25  	serviceName string
    26  	conf        config.Config
    27  	stop        chan bool
    28  }
    29  
    30  func NewService(cfg config.Config, points config.EndPoints, registry registry.Registry) (service.Service, error) {
    31  
    32  	// initial consul client config
    33  	cli, err := NewClientWithPoints(points)
    34  	if err != nil {
    35  		return nil, err
    36  	}
    37  	logger.Info("Consul.service: create consul client")
    38  	id := fmt.Sprintf("service: %s", cfg.Server.To())
    39  	serviceName := cfg.Node.NameWith("")
    40  
    41  	reg := &consul.AgentServiceRegistration{
    42  		ID:      id,
    43  		Name:    serviceName,
    44  		Tags:    cfg.Tags,
    45  		Port:    cfg.Server.Port,
    46  		Address: cfg.Server.Host,
    47  	}
    48  	logger.Info("Consul.service: register info= %+v", reg)
    49  	if err = cli.Agent().ServiceRegister(reg); err != nil {
    50  		return nil, result.Error(result.ErrServiceInternal,
    51  			fmt.Sprintf("CONSUL.SERVICE: register service= %v", err))
    52  	}
    53  
    54  	err = registerHealth(cfg.Check, id, serviceName, cli)
    55  	if err != nil {
    56  		return nil, result.Error(result.ErrServiceInternal,
    57  			fmt.Sprintf("[CONSUL.SERVICE] register service check : %v", err))
    58  	}
    59  
    60  	ser := &clService{
    61  		Base: Base{
    62  			client:  cli,
    63  			watcher: nil,
    64  		},
    65  		id:          id,
    66  		serviceName: serviceName,
    67  		conf:        cfg,
    68  		stop:        make(chan bool)}
    69  
    70  	return ser, nil
    71  }
    72  
    73  func registerHealth(conf server.Health, id string, name string, client *consul.Client) error {
    74  	// initial register service check
    75  	asc := consul.AgentServiceCheck{Status: consul.HealthPassing}
    76  
    77  	duration := fmt.Sprintf("%ds", conf.Interval)
    78  
    79  	if conf.Ttl {
    80  		asc.TTL = duration
    81  	} else {
    82  		asc.Interval = duration
    83  		switch conf.Protocol {
    84  		case server.KGRpcProtocol:
    85  			asc.GRPC = conf.URL.To()
    86  		case server.KHttpProtocol:
    87  			asc.HTTP = conf.URL.To()
    88  		case server.KTCPProtocol:
    89  			asc.TCP = conf.URL.To()
    90  		}
    91  	}
    92  	check := &consul.AgentCheckRegistration{
    93  		ID:                id,
    94  		ServiceID:         id,
    95  		Name:              name,
    96  		AgentServiceCheck: asc,
    97  	}
    98  	return client.Agent().CheckRegister(check)
    99  }
   100  
   101  // Start
   102  /**
   103  * Service interface
   104  * 使用 goroutine  go Start
   105   */
   106  func (s *clService) Start() error {
   107  	system.ChildRunning(s.keepAlive)
   108  	return nil
   109  }
   110  
   111  // Stop Service interface
   112  func (s *clService) Stop() {
   113  	system.Stop(time.Second, s.stop)
   114  }
   115  
   116  func (s *clService) keepAlive() {
   117  	ticker := time.NewTicker(time.Second * s.conf.Check.Interval)
   118  	defer ticker.Stop()
   119  	for {
   120  		select {
   121  		case <-s.stop:
   122  			s.revoke()
   123  			s.stop <- true
   124  			return
   125  
   126  		case <-ticker.C:
   127  			if err := s.client.Agent().UpdateTTL(s.id, "", consul.HealthPassing); err != nil {
   128  				logger.Error("Consul.service: update ttl err= %v", err)
   129  			}
   130  
   131  		case <-system.Closed():
   132  			logger.Error("Consul.service: server stop because system closed")
   133  			s.revoke()
   134  			return
   135  		}
   136  	}
   137  }
   138  
   139  func (s *clService) revoke() {
   140  
   141  	err := s.client.Agent().ServiceDeregister(s.id)
   142  	if err != nil {
   143  		logger.Error("Consul.service: deregister service err= %v", err)
   144  	}
   145  
   146  	err = s.client.Agent().CheckDeregister(s.id)
   147  	if err != nil {
   148  		logger.Error("Consul.service: deregister check err= %v", err)
   149  	}
   150  	logger.Info("Consul.service: deregister")
   151  }