github.com/micro/go-micro/v2@v2.9.1/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 "github.com/micro/go-micro/v2/logger" 11 "github.com/micro/go-micro/v2/registry" 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 if logger.V(logger.DebugLevel, logger.DefaultLogger) { 79 logger.Debugf("Registry TTL expired for node %s of service %s", n.Id, name) 80 } 81 delete(m.records[name][version].Nodes, id) 82 } 83 } 84 } 85 } 86 m.Unlock() 87 } 88 } 89 } 90 91 func (m *Registry) sendEvent(r *registry.Result) { 92 m.RLock() 93 watchers := make([]*Watcher, 0, len(m.watchers)) 94 for _, w := range m.watchers { 95 watchers = append(watchers, w) 96 } 97 m.RUnlock() 98 99 for _, w := range watchers { 100 select { 101 case <-w.exit: 102 m.Lock() 103 delete(m.watchers, w.id) 104 m.Unlock() 105 default: 106 select { 107 case w.res <- r: 108 case <-time.After(sendEventTime): 109 } 110 } 111 } 112 } 113 114 func (m *Registry) Init(opts ...registry.Option) error { 115 for _, o := range opts { 116 o(&m.options) 117 } 118 119 // add services 120 m.Lock() 121 defer m.Unlock() 122 123 records := getServiceRecords(m.options.Context) 124 for name, record := range records { 125 // add a whole new service including all of its versions 126 if _, ok := m.records[name]; !ok { 127 m.records[name] = record 128 continue 129 } 130 // add the versions of the service we dont track yet 131 for version, r := range record { 132 if _, ok := m.records[name][version]; !ok { 133 m.records[name][version] = r 134 continue 135 } 136 } 137 } 138 139 return nil 140 } 141 142 func (m *Registry) Options() registry.Options { 143 return m.options 144 } 145 146 func (m *Registry) Register(s *registry.Service, opts ...registry.RegisterOption) error { 147 m.Lock() 148 defer m.Unlock() 149 150 var options registry.RegisterOptions 151 for _, o := range opts { 152 o(&options) 153 } 154 155 r := serviceToRecord(s, options.TTL) 156 157 if _, ok := m.records[s.Name]; !ok { 158 m.records[s.Name] = make(map[string]*record) 159 } 160 161 if _, ok := m.records[s.Name][s.Version]; !ok { 162 m.records[s.Name][s.Version] = r 163 if logger.V(logger.DebugLevel, logger.DefaultLogger) { 164 logger.Debugf("Registry added new service: %s, version: %s", s.Name, s.Version) 165 } 166 go m.sendEvent(®istry.Result{Action: "update", Service: s}) 167 return nil 168 } 169 170 addedNodes := false 171 for _, n := range s.Nodes { 172 if _, ok := m.records[s.Name][s.Version].Nodes[n.Id]; !ok { 173 addedNodes = true 174 metadata := make(map[string]string) 175 for k, v := range n.Metadata { 176 metadata[k] = v 177 m.records[s.Name][s.Version].Nodes[n.Id] = &node{ 178 Node: ®istry.Node{ 179 Id: n.Id, 180 Address: n.Address, 181 Metadata: metadata, 182 }, 183 TTL: options.TTL, 184 LastSeen: time.Now(), 185 } 186 } 187 } 188 } 189 190 if addedNodes { 191 if logger.V(logger.DebugLevel, logger.DefaultLogger) { 192 logger.Debugf("Registry added new node to service: %s, version: %s", s.Name, s.Version) 193 } 194 go m.sendEvent(®istry.Result{Action: "update", Service: s}) 195 return nil 196 } 197 198 // refresh TTL and timestamp 199 for _, n := range s.Nodes { 200 if logger.V(logger.DebugLevel, logger.DefaultLogger) { 201 logger.Debugf("Updated registration for service: %s, version: %s", s.Name, s.Version) 202 } 203 m.records[s.Name][s.Version].Nodes[n.Id].TTL = options.TTL 204 m.records[s.Name][s.Version].Nodes[n.Id].LastSeen = time.Now() 205 } 206 207 return nil 208 } 209 210 func (m *Registry) Deregister(s *registry.Service, opts ...registry.DeregisterOption) error { 211 m.Lock() 212 defer m.Unlock() 213 214 if _, ok := m.records[s.Name]; ok { 215 if _, ok := m.records[s.Name][s.Version]; ok { 216 for _, n := range s.Nodes { 217 if _, ok := m.records[s.Name][s.Version].Nodes[n.Id]; ok { 218 if logger.V(logger.DebugLevel, logger.DefaultLogger) { 219 logger.Debugf("Registry removed node from service: %s, version: %s", s.Name, s.Version) 220 } 221 delete(m.records[s.Name][s.Version].Nodes, n.Id) 222 } 223 } 224 if len(m.records[s.Name][s.Version].Nodes) == 0 { 225 delete(m.records[s.Name], s.Version) 226 if logger.V(logger.DebugLevel, logger.DefaultLogger) { 227 logger.Debugf("Registry removed service: %s, version: %s", s.Name, s.Version) 228 } 229 } 230 } 231 if len(m.records[s.Name]) == 0 { 232 delete(m.records, s.Name) 233 if logger.V(logger.DebugLevel, logger.DefaultLogger) { 234 logger.Debugf("Registry removed service: %s", s.Name) 235 } 236 } 237 go m.sendEvent(®istry.Result{Action: "delete", Service: s}) 238 } 239 240 return nil 241 } 242 243 func (m *Registry) GetService(name string, opts ...registry.GetOption) ([]*registry.Service, error) { 244 m.RLock() 245 defer m.RUnlock() 246 247 records, ok := m.records[name] 248 if !ok { 249 return nil, registry.ErrNotFound 250 } 251 252 services := make([]*registry.Service, len(m.records[name])) 253 i := 0 254 for _, record := range records { 255 services[i] = recordToService(record) 256 i++ 257 } 258 259 return services, nil 260 } 261 262 func (m *Registry) ListServices(opts ...registry.ListOption) ([]*registry.Service, error) { 263 m.RLock() 264 defer m.RUnlock() 265 266 var services []*registry.Service 267 for _, records := range m.records { 268 for _, record := range records { 269 services = append(services, recordToService(record)) 270 } 271 } 272 273 return services, nil 274 } 275 276 func (m *Registry) Watch(opts ...registry.WatchOption) (registry.Watcher, error) { 277 var wo registry.WatchOptions 278 for _, o := range opts { 279 o(&wo) 280 } 281 282 w := &Watcher{ 283 exit: make(chan bool), 284 res: make(chan *registry.Result), 285 id: uuid.New().String(), 286 wo: wo, 287 } 288 289 m.Lock() 290 m.watchers[w.id] = w 291 m.Unlock() 292 293 return w, nil 294 } 295 296 func (m *Registry) String() string { 297 return "memory" 298 }