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

     1  package registry
     2  
     3  import (
     4  	"context"
     5  	"sync"
     6  	"time"
     7  
     8  	"github.com/google/uuid"
     9  	"gitee.com/sasukebo/go-micro/v4/logger"
    10  )
    11  
    12  var (
    13  	sendEventTime = 10 * time.Millisecond
    14  	ttlPruneTime  = time.Second
    15  )
    16  
    17  type node struct {
    18  	*Node
    19  	TTL      time.Duration
    20  	LastSeen time.Time
    21  }
    22  
    23  type record struct {
    24  	Name      string
    25  	Version   string
    26  	Metadata  map[string]string
    27  	Nodes     map[string]*node
    28  	Endpoints []*Endpoint
    29  }
    30  
    31  type memRegistry struct {
    32  	options Options
    33  
    34  	sync.RWMutex
    35  	records  map[string]map[string]*record
    36  	watchers map[string]*memWatcher
    37  }
    38  
    39  func NewMemoryRegistry(opts ...Option) Registry {
    40  	options := Options{
    41  		Context: context.Background(),
    42  	}
    43  
    44  	for _, o := range opts {
    45  		o(&options)
    46  	}
    47  
    48  	records := getServiceRecords(options.Context)
    49  	if records == nil {
    50  		records = make(map[string]map[string]*record)
    51  	}
    52  
    53  	reg := &memRegistry{
    54  		options:  options,
    55  		records:  records,
    56  		watchers: make(map[string]*memWatcher),
    57  	}
    58  
    59  	go reg.ttlPrune()
    60  
    61  	return reg
    62  }
    63  
    64  func (m *memRegistry) ttlPrune() {
    65  	prune := time.NewTicker(ttlPruneTime)
    66  	defer prune.Stop()
    67  
    68  	for {
    69  		select {
    70  		case <-prune.C:
    71  			m.Lock()
    72  			for name, records := range m.records {
    73  				for version, record := range records {
    74  					for id, n := range record.Nodes {
    75  						if n.TTL != 0 && time.Since(n.LastSeen) > n.TTL {
    76  							if logger.V(logger.DebugLevel, logger.DefaultLogger) {
    77  								logger.Debugf("Registry TTL expired for node %s of service %s", n.Id, name)
    78  							}
    79  							delete(m.records[name][version].Nodes, id)
    80  						}
    81  					}
    82  				}
    83  			}
    84  			m.Unlock()
    85  		}
    86  	}
    87  }
    88  
    89  func (m *memRegistry) sendEvent(r *Result) {
    90  	m.RLock()
    91  	watchers := make([]*memWatcher, 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 *memRegistry) Init(opts ...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 *memRegistry) Options() Options {
   141  	return m.options
   142  }
   143  
   144  func (m *memRegistry) Register(s *Service, opts ...RegisterOption) error {
   145  	m.Lock()
   146  	defer m.Unlock()
   147  
   148  	var options 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  		if logger.V(logger.DebugLevel, logger.DefaultLogger) {
   162  			logger.Debugf("Registry added new service: %s, version: %s", s.Name, s.Version)
   163  		}
   164  		go m.sendEvent(&Result{Action: "update", Service: s})
   165  		return nil
   166  	}
   167  
   168  	addedNodes := false
   169  	for _, n := range s.Nodes {
   170  		if _, ok := m.records[s.Name][s.Version].Nodes[n.Id]; !ok {
   171  			addedNodes = true
   172  			metadata := make(map[string]string)
   173  			for k, v := range n.Metadata {
   174  				metadata[k] = v
   175  				m.records[s.Name][s.Version].Nodes[n.Id] = &node{
   176  					Node: &Node{
   177  						Id:       n.Id,
   178  						Address:  n.Address,
   179  						Metadata: metadata,
   180  					},
   181  					TTL:      options.TTL,
   182  					LastSeen: time.Now(),
   183  				}
   184  			}
   185  		}
   186  	}
   187  
   188  	if addedNodes {
   189  		if logger.V(logger.DebugLevel, logger.DefaultLogger) {
   190  			logger.Debugf("Registry added new node to service: %s, version: %s", s.Name, s.Version)
   191  		}
   192  		go m.sendEvent(&Result{Action: "update", Service: s})
   193  		return nil
   194  	}
   195  
   196  	// refresh TTL and timestamp
   197  	for _, n := range s.Nodes {
   198  		if logger.V(logger.DebugLevel, logger.DefaultLogger) {
   199  			logger.Debugf("Updated registration for service: %s, version: %s", s.Name, s.Version)
   200  		}
   201  		m.records[s.Name][s.Version].Nodes[n.Id].TTL = options.TTL
   202  		m.records[s.Name][s.Version].Nodes[n.Id].LastSeen = time.Now()
   203  	}
   204  
   205  	return nil
   206  }
   207  
   208  func (m *memRegistry) Deregister(s *Service, opts ...DeregisterOption) error {
   209  	m.Lock()
   210  	defer m.Unlock()
   211  
   212  	if _, ok := m.records[s.Name]; ok {
   213  		if _, ok := m.records[s.Name][s.Version]; ok {
   214  			for _, n := range s.Nodes {
   215  				if _, ok := m.records[s.Name][s.Version].Nodes[n.Id]; ok {
   216  					if logger.V(logger.DebugLevel, logger.DefaultLogger) {
   217  						logger.Debugf("Registry removed node from service: %s, version: %s", s.Name, s.Version)
   218  					}
   219  					delete(m.records[s.Name][s.Version].Nodes, n.Id)
   220  				}
   221  			}
   222  			if len(m.records[s.Name][s.Version].Nodes) == 0 {
   223  				delete(m.records[s.Name], s.Version)
   224  				if logger.V(logger.DebugLevel, logger.DefaultLogger) {
   225  					logger.Debugf("Registry removed service: %s, version: %s", s.Name, s.Version)
   226  				}
   227  			}
   228  		}
   229  		if len(m.records[s.Name]) == 0 {
   230  			delete(m.records, s.Name)
   231  			if logger.V(logger.DebugLevel, logger.DefaultLogger) {
   232  				logger.Debugf("Registry removed service: %s", s.Name)
   233  			}
   234  		}
   235  		go m.sendEvent(&Result{Action: "delete", Service: s})
   236  	}
   237  
   238  	return nil
   239  }
   240  
   241  func (m *memRegistry) GetService(name string, opts ...GetOption) ([]*Service, error) {
   242  	m.RLock()
   243  	defer m.RUnlock()
   244  
   245  	records, ok := m.records[name]
   246  	if !ok {
   247  		return nil, ErrNotFound
   248  	}
   249  
   250  	services := make([]*Service, len(m.records[name]))
   251  	i := 0
   252  	for _, record := range records {
   253  		services[i] = recordToService(record)
   254  		i++
   255  	}
   256  
   257  	return services, nil
   258  }
   259  
   260  func (m *memRegistry) ListServices(opts ...ListOption) ([]*Service, error) {
   261  	m.RLock()
   262  	defer m.RUnlock()
   263  
   264  	var services []*Service
   265  	for _, records := range m.records {
   266  		for _, record := range records {
   267  			services = append(services, recordToService(record))
   268  		}
   269  	}
   270  
   271  	return services, nil
   272  }
   273  
   274  func (m *memRegistry) Watch(opts ...WatchOption) (Watcher, error) {
   275  	var wo WatchOptions
   276  	for _, o := range opts {
   277  		o(&wo)
   278  	}
   279  
   280  	w := &memWatcher{
   281  		exit: make(chan bool),
   282  		res:  make(chan *Result),
   283  		id:   uuid.New().String(),
   284  		wo:   wo,
   285  	}
   286  
   287  	m.Lock()
   288  	m.watchers[w.id] = w
   289  	m.Unlock()
   290  
   291  	return w, nil
   292  }
   293  
   294  func (m *memRegistry) String() string {
   295  	return "memory"
   296  }