gitee.com/liuxuezhan/go-micro-v1.18.0@v1.0.0/registry/memory/memory.go (about)

     1  // Package memory provides an in-memory registry
     2  package memory
     3  
     4  import (
     5  	"context"
     6  	"sync"
     7  	"time"
     8  
     9  	"github.com/google/uuid"
    10  	"gitee.com/liuxuezhan/go-micro-v1.18.0/registry"
    11  	"gitee.com/liuxuezhan/go-micro-v1.18.0/util/log"
    12  )
    13  
    14  var (
    15  	sendEventTime = 10 * time.Millisecond
    16  	ttlPruneTime  = time.Second
    17  )
    18  
    19  type node struct {
    20  	*registry.Node
    21  	TTL      time.Duration
    22  	LastSeen time.Time
    23  }
    24  
    25  type record struct {
    26  	Name      string
    27  	Version   string
    28  	Metadata  map[string]string
    29  	Nodes     map[string]*node
    30  	Endpoints []*registry.Endpoint
    31  }
    32  
    33  type Registry struct {
    34  	options registry.Options
    35  
    36  	sync.RWMutex
    37  	records  map[string]map[string]*record
    38  	watchers map[string]*Watcher
    39  }
    40  
    41  func NewRegistry(opts ...registry.Option) registry.Registry {
    42  	options := registry.Options{
    43  		Context: context.Background(),
    44  	}
    45  
    46  	for _, o := range opts {
    47  		o(&options)
    48  	}
    49  
    50  	records := getServiceRecords(options.Context)
    51  	if records == nil {
    52  		records = make(map[string]map[string]*record)
    53  	}
    54  
    55  	reg := &Registry{
    56  		options:  options,
    57  		records:  records,
    58  		watchers: make(map[string]*Watcher),
    59  	}
    60  
    61  	go reg.ttlPrune()
    62  
    63  	return reg
    64  }
    65  
    66  func (m *Registry) ttlPrune() {
    67  	prune := time.NewTicker(ttlPruneTime)
    68  	defer prune.Stop()
    69  
    70  	for {
    71  		select {
    72  		case <-prune.C:
    73  			m.Lock()
    74  			for name, records := range m.records {
    75  				for version, record := range records {
    76  					for id, n := range record.Nodes {
    77  						if n.TTL != 0 && time.Since(n.LastSeen) > n.TTL {
    78  							log.Debugf("Registry TTL expired for node %s of service %s", n.Id, name)
    79  							delete(m.records[name][version].Nodes, id)
    80  						}
    81  					}
    82  				}
    83  			}
    84  			m.Unlock()
    85  		}
    86  	}
    87  }
    88  
    89  func (m *Registry) sendEvent(r *registry.Result) {
    90  	m.RLock()
    91  	watchers := make([]*Watcher, 0, len(m.watchers))
    92  	for _, w := range m.watchers {
    93  		watchers = append(watchers, w)
    94  	}
    95  	m.RUnlock()
    96  
    97  	for _, w := range watchers {
    98  		select {
    99  		case <-w.exit:
   100  			m.Lock()
   101  			delete(m.watchers, w.id)
   102  			m.Unlock()
   103  		default:
   104  			select {
   105  			case w.res <- r:
   106  			case <-time.After(sendEventTime):
   107  			}
   108  		}
   109  	}
   110  }
   111  
   112  func (m *Registry) Init(opts ...registry.Option) error {
   113  	for _, o := range opts {
   114  		o(&m.options)
   115  	}
   116  
   117  	// add services
   118  	m.Lock()
   119  	defer m.Unlock()
   120  
   121  	records := getServiceRecords(m.options.Context)
   122  	for name, record := range records {
   123  		// add a whole new service including all of its versions
   124  		if _, ok := m.records[name]; !ok {
   125  			m.records[name] = record
   126  			continue
   127  		}
   128  		// add the versions of the service we dont track yet
   129  		for version, r := range record {
   130  			if _, ok := m.records[name][version]; !ok {
   131  				m.records[name][version] = r
   132  				continue
   133  			}
   134  		}
   135  	}
   136  
   137  	return nil
   138  }
   139  
   140  func (m *Registry) Options() registry.Options {
   141  	return m.options
   142  }
   143  
   144  func (m *Registry) Register(s *registry.Service, opts ...registry.RegisterOption) error {
   145  	m.Lock()
   146  	defer m.Unlock()
   147  
   148  	var options registry.RegisterOptions
   149  	for _, o := range opts {
   150  		o(&options)
   151  	}
   152  
   153  	r := serviceToRecord(s, options.TTL)
   154  
   155  	if _, ok := m.records[s.Name]; !ok {
   156  		m.records[s.Name] = make(map[string]*record)
   157  	}
   158  
   159  	if _, ok := m.records[s.Name][s.Version]; !ok {
   160  		m.records[s.Name][s.Version] = r
   161  		log.Debugf("Registry added new service: %s, version: %s", s.Name, s.Version)
   162  		go m.sendEvent(&registry.Result{Action: "update", Service: s})
   163  		return nil
   164  	}
   165  
   166  	addedNodes := false
   167  	for _, n := range s.Nodes {
   168  		if _, ok := m.records[s.Name][s.Version].Nodes[n.Id]; !ok {
   169  			addedNodes = true
   170  			metadata := make(map[string]string)
   171  			for k, v := range n.Metadata {
   172  				metadata[k] = v
   173  				m.records[s.Name][s.Version].Nodes[n.Id] = &node{
   174  					Node: &registry.Node{
   175  						Id:       n.Id,
   176  						Address:  n.Address,
   177  						Metadata: metadata,
   178  					},
   179  					TTL:      options.TTL,
   180  					LastSeen: time.Now(),
   181  				}
   182  			}
   183  		}
   184  	}
   185  
   186  	if addedNodes {
   187  		log.Debugf("Registry added new node to service: %s, version: %s", s.Name, s.Version)
   188  		go m.sendEvent(&registry.Result{Action: "update", Service: s})
   189  		return nil
   190  	}
   191  
   192  	// refresh TTL and timestamp
   193  	for _, n := range s.Nodes {
   194  		log.Debugf("Updated registration for service: %s, version: %s", s.Name, s.Version)
   195  		m.records[s.Name][s.Version].Nodes[n.Id].TTL = options.TTL
   196  		m.records[s.Name][s.Version].Nodes[n.Id].LastSeen = time.Now()
   197  	}
   198  
   199  	return nil
   200  }
   201  
   202  func (m *Registry) Deregister(s *registry.Service) error {
   203  	m.Lock()
   204  	defer m.Unlock()
   205  
   206  	if _, ok := m.records[s.Name]; ok {
   207  		if _, ok := m.records[s.Name][s.Version]; ok {
   208  			for _, n := range s.Nodes {
   209  				if _, ok := m.records[s.Name][s.Version].Nodes[n.Id]; ok {
   210  					log.Debugf("Registry removed node from service: %s, version: %s", s.Name, s.Version)
   211  					delete(m.records[s.Name][s.Version].Nodes, n.Id)
   212  				}
   213  			}
   214  			if len(m.records[s.Name][s.Version].Nodes) == 0 {
   215  				delete(m.records[s.Name], s.Version)
   216  				log.Debugf("Registry removed service: %s, version: %s", s.Name, s.Version)
   217  			}
   218  		}
   219  		if len(m.records[s.Name]) == 0 {
   220  			delete(m.records, s.Name)
   221  			log.Debugf("Registry removed service: %s", s.Name)
   222  		}
   223  		go m.sendEvent(&registry.Result{Action: "delete", Service: s})
   224  	}
   225  
   226  	return nil
   227  }
   228  
   229  func (m *Registry) GetService(name string) ([]*registry.Service, error) {
   230  	m.RLock()
   231  	defer m.RUnlock()
   232  
   233  	records, ok := m.records[name]
   234  	if !ok {
   235  		return nil, registry.ErrNotFound
   236  	}
   237  
   238  	services := make([]*registry.Service, len(m.records[name]))
   239  	i := 0
   240  	for _, record := range records {
   241  		services[i] = recordToService(record)
   242  		i++
   243  	}
   244  
   245  	return services, nil
   246  }
   247  
   248  func (m *Registry) ListServices() ([]*registry.Service, error) {
   249  	m.RLock()
   250  	defer m.RUnlock()
   251  
   252  	var services []*registry.Service
   253  	for _, records := range m.records {
   254  		for _, record := range records {
   255  			services = append(services, recordToService(record))
   256  		}
   257  	}
   258  
   259  	return services, nil
   260  }
   261  
   262  func (m *Registry) Watch(opts ...registry.WatchOption) (registry.Watcher, error) {
   263  	var wo registry.WatchOptions
   264  	for _, o := range opts {
   265  		o(&wo)
   266  	}
   267  
   268  	w := &Watcher{
   269  		exit: make(chan bool),
   270  		res:  make(chan *registry.Result),
   271  		id:   uuid.New().String(),
   272  		wo:   wo,
   273  	}
   274  
   275  	m.Lock()
   276  	m.watchers[w.id] = w
   277  	m.Unlock()
   278  
   279  	return w, nil
   280  }
   281  
   282  func (m *Registry) String() string {
   283  	return "memory"
   284  }