go-micro.dev/v5@v5.12.0/registry/memory.go (about)

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