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

     1  package zookeeper
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"gitee.com/h79/goutils/common/logger"
     7  	"gitee.com/h79/goutils/common/system"
     8  	"gitee.com/h79/goutils/discovery/config"
     9  	"gitee.com/h79/goutils/discovery/registry"
    10  	"gitee.com/h79/goutils/discovery/service"
    11  	"github.com/go-zookeeper/zk"
    12  	"sync"
    13  	"time"
    14  )
    15  
    16  var _ service.Service = (*zkService)(nil)
    17  
    18  type zkService struct {
    19  	Base
    20  	id     string
    21  	conf   config.Config
    22  	locker sync.Mutex
    23  	stop   chan bool
    24  }
    25  
    26  // NewService
    27  // 注册一个服务
    28  func NewService(cfg config.Config, points config.EndPoints, registry registry.Registry) (service.Service, error) {
    29  
    30  	cli, err := NewClientZk(&points, cfg.Node, 30)
    31  	if err != nil {
    32  		return nil, err
    33  	}
    34  	logger.Info("Zookeeper.service: create client")
    35  
    36  	s, err := NewServiceWith(cli, cfg)
    37  	if err != nil {
    38  		cli.Close()
    39  	}
    40  	return s, err
    41  }
    42  
    43  func NewServiceWith(cli *zk.Conn, cfg config.Config) (service.Service, error) {
    44  
    45  	id := fmt.Sprintf("service: %s", cfg.Server.To())
    46  
    47  	path := cfg.Node.NameWith("")
    48  
    49  	exists, _, err := cli.Exists(path)
    50  	if err != nil {
    51  		return nil, err
    52  	}
    53  
    54  	if !exists { //不存在,注册一个服务
    55  		_, err := cli.Create(path, []byte(""), 0, zk.WorldACL(zk.PermAll))
    56  		if err != nil && err != zk.ErrNodeExists {
    57  
    58  			return nil, err
    59  		}
    60  	}
    61  
    62  	data, err := json.Marshal(&cfg.Server)
    63  	if err != nil {
    64  		return nil, err
    65  	}
    66  
    67  	path += "/n"
    68  	_, err = cli.CreateProtectedEphemeralSequential(path, data, zk.WorldACL(zk.PermAll))
    69  	if err != nil {
    70  		return nil, err
    71  	}
    72  
    73  	ser := &zkService{Base: Base{
    74  		conn: cli,
    75  	}, id: id, conf: cfg, stop: make(chan bool)}
    76  
    77  	return ser, nil
    78  }
    79  
    80  // Start
    81  /**
    82  * Service interface
    83  * 使用 goroutine  go Start
    84   */
    85  func (s *zkService) Start() error {
    86  	system.ChildRunning(s.keepAlive)
    87  	system.ChildRunning(s.close)
    88  	return nil
    89  }
    90  
    91  // Stop interface
    92  func (s *zkService) Stop() {
    93  	system.Stop(time.Second, s.stop)
    94  }
    95  
    96  func (s *zkService) close() {
    97  	for {
    98  		select {
    99  		case <-s.stop:
   100  			s.revoke()
   101  			s.stop <- true
   102  			return
   103  
   104  		case <-system.Closed():
   105  			logger.Error("Zookeeper.service: close because system close")
   106  			s.revoke()
   107  			return
   108  		}
   109  	}
   110  }
   111  
   112  func (s *zkService) keepAlive() {
   113  	if !s.conf.Check.Ttl {
   114  		return
   115  	}
   116  	ticker := time.NewTicker(time.Second * 8)
   117  	for {
   118  		select {
   119  		case err := <-s.stop:
   120  			logger.Error("Zookeeper.service: keepAlive stop, err= %v", err)
   121  			return
   122  
   123  		case <-ticker.C:
   124  			var path = s.conf.Node.NameWith("")
   125  			if _, err := s.conn.CreateTTL(path, nil, zk.FlagTTL, zk.WorldACL(zk.PermAll), 10000); err != nil {
   126  				logger.Error("Zookeeper.service: update ttl err= %v", err)
   127  			}
   128  
   129  		case <-system.Closed():
   130  			return
   131  		}
   132  	}
   133  }
   134  
   135  func (s *zkService) revoke() {
   136  	s.conn.Close()
   137  }