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 }