github.com/moleculer-go/moleculer@v0.3.3/registry/eventCatalog.go (about) 1 package registry 2 3 import ( 4 "fmt" 5 "runtime/debug" 6 "sync" 7 8 "github.com/moleculer-go/moleculer" 9 "github.com/moleculer-go/moleculer/service" 10 "github.com/moleculer-go/moleculer/strategy" 11 log "github.com/sirupsen/logrus" 12 ) 13 14 type EventEntry struct { 15 targetNodeID string 16 service *service.Service 17 event *service.Event 18 isLocal bool 19 } 20 21 func (eventEntry EventEntry) TargetNodeID() string { 22 return eventEntry.targetNodeID 23 } 24 25 func (eventEntry *EventEntry) IsLocal() bool { 26 return eventEntry.isLocal 27 } 28 29 func (eventEntry *EventEntry) String() string { 30 return fmt.Sprint("EventEntry Node -> ", eventEntry.targetNodeID, 31 " - Service: ", eventEntry.event.ServiceName(), 32 " - Event Name: ", eventEntry.event.Name(), 33 " - Group: ", eventEntry.event.Group()) 34 } 35 36 func catchEventError(context moleculer.BrokerContext, logger *log.Entry) { 37 if err := recover(); err != nil { 38 logger.Error("Event handler failed :( event: ", context.EventName(), " error: ", err, "\n[Stack Trace]: ", string(debug.Stack())) 39 } 40 } 41 42 func (eventEntry *EventEntry) emitLocalEvent(context moleculer.BrokerContext) { 43 logger := context.Logger().WithField("eventCatalog", "emitLocalEvent") 44 logger.Debug("Invoking local event: ", context.EventName()) 45 defer catchEventError(context, logger) 46 handler := eventEntry.event.Handler() 47 handler(context.(moleculer.Context), context.Payload()) 48 logger.Trace("After invoking local event: ", context.EventName()) 49 } 50 51 type EventCatalog struct { 52 events sync.Map 53 logger *log.Entry 54 } 55 56 func CreateEventCatalog(logger *log.Entry) *EventCatalog { 57 events := sync.Map{} 58 return &EventCatalog{events: events, logger: logger} 59 } 60 61 // Add a new event to the catalog. 62 func (eventCatalog *EventCatalog) Add(event service.Event, service *service.Service, local bool) { 63 entry := EventEntry{service.NodeID(), service, &event, local} 64 name := event.Name() 65 eventCatalog.logger.Debug("Add event name: ", name, " serviceName: ", event.ServiceName()) 66 list, exists := eventCatalog.events.Load(name) 67 if !exists { 68 list = []EventEntry{entry} 69 } else { 70 list = append(list.([]EventEntry), entry) 71 } 72 eventCatalog.events.Store(name, list) 73 } 74 75 func (eventCatalog *EventCatalog) Update(nodeID string, name string, updates map[string]interface{}) { 76 //TODO .. the only thing that can be udpated is the Event Schema (validation) and that does not exist yet 77 } 78 79 func (eventCatalog *EventCatalog) listByName() map[string][]EventEntry { 80 result := make(map[string][]EventEntry) 81 eventCatalog.events.Range(func(key, value interface{}) bool { 82 result[key.(string)] = value.([]EventEntry) 83 return true 84 }) 85 return result 86 } 87 88 func (eventCatalog *EventCatalog) Remove(nodeID string, name string) { 89 removed := 0 90 list, exists := eventCatalog.events.Load(name) 91 if !exists { 92 return 93 } 94 var newList []EventEntry 95 for _, event := range list.([]EventEntry) { 96 if event.targetNodeID != nodeID { 97 newList = append(newList, event) 98 } else { 99 removed++ 100 } 101 } 102 eventCatalog.events.Store(name, newList) 103 } 104 105 // RemoveByNode remove events for the given nodeID. 106 func (eventCatalog *EventCatalog) RemoveByNode(nodeID string) { 107 removed := 0 108 eventCatalog.events.Range(func(key, value interface{}) bool { 109 name := key.(string) 110 events := value.([]EventEntry) 111 var toKeep []EventEntry 112 for _, event := range events { 113 if event.targetNodeID != nodeID { 114 toKeep = append(toKeep, event) 115 } else { 116 removed++ 117 } 118 } 119 eventCatalog.events.Store(name, toKeep) 120 return true 121 }) 122 } 123 124 func matchGroup(event *service.Event, groups []string) bool { 125 if groups == nil || len(groups) == 0 { 126 return true 127 } 128 for _, group := range groups { 129 if event.Group() == group { 130 return true 131 } 132 } 133 return false 134 } 135 136 func findLocal(events []EventEntry) *EventEntry { 137 for _, item := range events { 138 if item.IsLocal() { 139 return &item 140 } 141 } 142 return nil 143 } 144 145 // Find find all events registered in this node and use the strategy to select and return the best one to be called. 146 func (eventCatalog *EventCatalog) Find(name string, groups []string, preferLocal bool, localOnly bool, stg strategy.Strategy) []*EventEntry { 147 events, exists := eventCatalog.events.Load(name) 148 if !exists { 149 return make([]*EventEntry, 0) 150 } 151 eventCatalog.logger.Trace("event: ", name, " started: ", events) 152 153 entryGroups := make(map[string][]EventEntry) 154 for _, entry := range events.([]EventEntry) { 155 if localOnly && !entry.isLocal { 156 continue 157 } 158 if matchGroup(entry.event, groups) { 159 entryGroups[entry.event.Group()] = append(entryGroups[entry.event.Group()], entry) 160 } 161 } 162 var result []*EventEntry 163 for _, entries := range entryGroups { 164 if local := findLocal(entries); preferLocal && local != nil { 165 eventCatalog.logger.Trace("event: ", name, " found local: ", local) 166 result = append(result, local) 167 } else if len(entries) == 1 { 168 eventCatalog.logger.Debug("event: ", name, " found a single one :) ", entries[0]) 169 result = append(result, &entries[0]) 170 } else if len(entries) > 1 { 171 if stg == nil { 172 eventCatalog.logger.Debug("event: ", name, " no strategy. return all entries: ", entries) 173 for _, entry := range entries { 174 result = append(result, &entry) 175 } 176 } else { 177 eventCatalog.logger.Debug("event: ", name, "using strategy to load balance between options: ", entries) 178 nodes := make([]strategy.Selector, len(entries)) 179 for index, entry := range entries { 180 nodes[index] = &entry 181 } 182 if selected := stg.Select(nodes); selected != nil { 183 entry := (*selected).(*EventEntry) 184 result = append(result, entry) 185 } 186 } 187 188 } 189 } 190 191 return result 192 } 193 194 func (eventCatalog *EventCatalog) list() []EventEntry { 195 var result []EventEntry 196 eventCatalog.events.Range(func(key, value interface{}) bool { 197 entries := value.([]EventEntry) 198 for _, item := range entries { 199 result = append(result, item) 200 } 201 return true 202 }) 203 return result 204 }