code.vegaprotocol.io/vega@v0.79.0/datanode/api/event_observer.go (about) 1 // Copyright (C) 2023 Gobalsky Labs Limited 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Affero General Public License as 5 // published by the Free Software Foundation, either version 3 of the 6 // License, or (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Affero General Public License for more details. 12 // 13 // You should have received a copy of the GNU Affero General Public License 14 // along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16 package api 17 18 import ( 19 "context" 20 "time" 21 22 "code.vegaprotocol.io/vega/core/events" 23 "code.vegaprotocol.io/vega/datanode/metrics" 24 "code.vegaprotocol.io/vega/libs/subscribers" 25 "code.vegaprotocol.io/vega/logging" 26 protoapi "code.vegaprotocol.io/vega/protos/vega/api/v1" 27 eventspb "code.vegaprotocol.io/vega/protos/vega/events/v1" 28 ) 29 30 type eventBusServer interface { 31 RecvMsg(m interface{}) error 32 Context() context.Context 33 Send(data []*eventspb.BusEvent) error 34 } 35 36 type eventObserver struct { 37 log *logging.Logger 38 eventService EventService 39 Config Config 40 } 41 42 type coreServiceEventBusServer struct { 43 stream protoapi.CoreService_ObserveEventBusServer 44 } 45 46 func (t coreServiceEventBusServer) RecvMsg(m interface{}) error { 47 return t.stream.RecvMsg(m) 48 } 49 50 func (t coreServiceEventBusServer) Context() context.Context { 51 return t.stream.Context() 52 } 53 54 func (t coreServiceEventBusServer) Send(data []*eventspb.BusEvent) error { 55 resp := &protoapi.ObserveEventBusResponse{ 56 Events: data, 57 } 58 return t.stream.Send(resp) 59 } 60 61 func (e *eventObserver) ObserveEventBus( 62 stream protoapi.CoreService_ObserveEventBusServer, 63 ) error { 64 return observeEventBus(e.log, e.Config, coreServiceEventBusServer{stream}, e.eventService) 65 } 66 67 func observeEventBus(log *logging.Logger, config Config, eventBusServer eventBusServer, eventService EventService) error { 68 defer metrics.StartActiveEventBusConnection()() 69 70 ctx, cfunc := context.WithCancel(eventBusServer.Context()) 71 defer cfunc() 72 73 // now we start listening for a few seconds in order to get at least the very first message 74 // this will be blocking until the connection by the client is closed 75 // and we will not start processing any events until we receive the original request 76 // indicating filters and batch size. 77 req, err := recvEventRequest(ctx, defaultReqTimeout, eventBusServer) 78 if err != nil { 79 log.Error("Error receiving event request", logging.Error(err)) 80 // client exited, nothing to do 81 return nil //nolint:nilerr 82 } 83 84 // now we will aggregate filter out of the initial request 85 types, err := events.ProtoToInternal(req.Type...) 86 if err != nil { 87 return formatE(ErrMalformedRequest, err) 88 } 89 90 metrics.StartEventBusActiveSubscriptionCount(types) 91 defer metrics.StopEventBusActiveSubscriptionCount(types) 92 93 var filters []subscribers.EventFilter 94 if len(req.MarketId) > 0 && len(req.PartyId) > 0 { 95 filters = append(filters, events.GetPartyAndMarketFilter(req.MarketId, req.PartyId)) 96 } else { 97 if len(req.MarketId) > 0 { 98 filters = append(filters, events.GetMarketIDFilter(req.MarketId)) 99 } 100 if len(req.PartyId) > 0 { 101 filters = append(filters, events.GetPartyIDFilter(req.PartyId)) 102 } 103 } 104 105 // number of retries to -1 to have pretty much unlimited retries 106 ch, bCh := eventService.ObserveEvents(ctx, config.StreamRetries, types, int(req.BatchSize), filters...) 107 defer close(bCh) 108 109 if req.BatchSize > 0 { 110 return observeEventsWithAck(ctx, log, eventBusServer, req.BatchSize, ch, bCh) 111 } 112 113 return observeEvents(ctx, log, eventBusServer, ch) 114 } 115 116 func observeEvents( 117 ctx context.Context, 118 log *logging.Logger, 119 stream eventBusServer, 120 ch <-chan []*eventspb.BusEvent, 121 ) error { 122 sentEventStatTicker := time.NewTicker(time.Second) 123 defer sentEventStatTicker.Stop() 124 publishedEvents := eventStats{} 125 126 for { 127 select { 128 case <-sentEventStatTicker.C: 129 publishedEvents.publishStats() 130 publishedEvents = eventStats{} 131 case data, ok := <-ch: 132 if !ok { 133 return nil 134 } 135 136 if err := stream.Send(data); err != nil { 137 log.Error("Error sending event on stream", logging.Error(err)) 138 return formatE(ErrStreamInternal, err) 139 } 140 publishedEvents.updateStats(data) 141 case <-ctx.Done(): 142 return formatE(ErrStreamInternal, ctx.Err()) 143 } 144 } 145 } 146 147 func observeEventsWithAck( 148 ctx context.Context, 149 log *logging.Logger, 150 stream eventBusServer, 151 batchSize int64, 152 ch <-chan []*eventspb.BusEvent, 153 bCh chan<- int, 154 ) error { 155 sentEventStatTicker := time.NewTicker(time.Second) 156 defer sentEventStatTicker.Stop() 157 publishedEvents := eventStats{} 158 159 for { 160 select { 161 case <-sentEventStatTicker.C: 162 publishedEvents.publishStats() 163 publishedEvents = eventStats{} 164 case data, ok := <-ch: 165 if !ok { 166 return nil 167 } 168 169 if err := stream.Send(data); err != nil { 170 log.Error("Error sending event on stream", logging.Error(err)) 171 return formatE(ErrStreamInternal, err) 172 } 173 publishedEvents.updateStats(data) 174 case <-ctx.Done(): 175 return formatE(ErrStreamInternal, ctx.Err()) 176 } 177 178 // now we try to read again the new size / ack 179 req, err := recvEventRequest(ctx, defaultReqTimeout, stream) 180 if err != nil { 181 return formatE(ErrStreamInternal, err) 182 } 183 184 if req.BatchSize != batchSize { 185 batchSize = req.BatchSize 186 bCh <- int(batchSize) 187 } 188 } 189 } 190 191 const defaultReqTimeout = time.Second * 5 192 193 func recvEventRequest(ctx context.Context, timeout time.Duration, stream eventBusServer) (*protoapi.ObserveEventBusRequest, error) { 194 type resp struct { 195 nb *protoapi.ObserveEventBusRequest 196 err error 197 } 198 199 oebCh := make(chan resp, 1) 200 201 go func() { 202 defer close(oebCh) 203 204 nb := &protoapi.ObserveEventBusRequest{} 205 err := stream.RecvMsg(nb) 206 207 oebCh <- resp{nb: nb, err: err} 208 }() 209 210 ctx, cancel := context.WithTimeout(ctx, timeout) 211 defer cancel() 212 213 select { 214 case rsp := <-oebCh: 215 return rsp.nb, rsp.err 216 case <-ctx.Done(): 217 return nil, ctx.Err() 218 } 219 } 220 221 // this needs to be greater than the highest eventspb.BusEvent event type. 222 const maxEventTypeOrdinal = 299 223 224 type eventStats struct { 225 eventCount [maxEventTypeOrdinal + 1]int 226 } 227 228 func (s *eventStats) updateStats(events []*eventspb.BusEvent) { 229 for _, event := range events { 230 eventType := event.Type 231 if int(eventType) > maxEventTypeOrdinal { 232 eventType = maxEventTypeOrdinal 233 } 234 s.eventCount[eventType] = s.eventCount[eventType] + 1 235 } 236 } 237 238 func (s eventStats) publishStats() { 239 for idx, count := range s.eventCount { 240 if count > 0 { 241 if idx == maxEventTypeOrdinal { 242 metrics.EventBusPublishedEventsAdd("Unknown", float64(count)) 243 } 244 245 eventName := eventspb.BusEventType_name[int32(idx)] 246 metrics.EventBusPublishedEventsAdd(eventName, float64(count)) 247 } 248 } 249 }