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 }