github.com/choria-io/go-choria@v0.28.1-0.20240416190746-b3bf9c7d5a45/broker/federation/choria_nats_egest.go (about) 1 // Copyright (c) 2017-2021, R.I. Pienaar and the Choria Project contributors 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 5 package federation 6 7 import ( 8 "context" 9 "fmt" 10 "strings" 11 12 "github.com/choria-io/go-choria/broker/federation/stats" 13 "github.com/choria-io/go-choria/inter" 14 "github.com/prometheus/client_golang/prometheus" 15 log "github.com/sirupsen/logrus" 16 ) 17 18 func NewChoriaNatsEgest(workers int, mode int, capacity int, broker *FederationBroker, logger *log.Entry) (*pooledWorker, error) { 19 worker, err := PooledWorkerFactory("choria_nats_egest", workers, mode, capacity, broker, logger, func(ctx context.Context, self *pooledWorker, i int, logger *log.Entry) { 20 defer self.wg.Done() 21 22 var nc inter.Connector 23 var err error 24 25 nc, err = self.connection.NewConnector(ctx, self.servers, self.Name(), logger) 26 if err != nil { 27 logger.Errorf("Could not start NATS connection for worker %d: %s", i, err) 28 return 29 } 30 31 workeri := fmt.Sprintf("%d", i) 32 mname := nameForConnectionMode(mode) 33 rctr := stats.ReceivedMsgsCtr.WithLabelValues("nats_egest", workeri, mname, self.broker.Name, self.broker.identity) 34 pctr := stats.PublishedMsgsCtr.WithLabelValues("nats_egest", workeri, mname, self.broker.Name, self.broker.identity) 35 ectr := stats.ErrorCtr.WithLabelValues("nats_egest", workeri, mname, self.broker.Name, self.broker.identity) 36 timer := stats.ProcessTime.WithLabelValues("nats_egest", workeri, mname, self.broker.Name, self.broker.identity) 37 38 handler := func(cm chainmessage) { 39 obs := prometheus.NewTimer(timer) 40 defer obs.ObserveDuration() 41 42 if len(cm.Targets) == 0 { 43 logger.Errorf("Received message '%s' with no targets, discarding: %#v", cm.RequestID, cm) 44 ectr.Inc() 45 return 46 } 47 48 rctr.Inc() 49 50 logger.Debugf("Publishing message '%s' to %d target(s)", cm.RequestID, len(cm.Targets)) 51 52 cm.Seen = append(cm.Seen, fmt.Sprintf("%s:%d", self.Name(), i)) 53 cm.Seen = append(cm.Seen, nc.ConnectedServer()) 54 55 if len(cm.Seen) >= 3 { 56 mid := fmt.Sprintf("%s (%s)", self.choria.Configuration().Identity, strings.Join(cm.Seen[1:len(cm.Seen)-1], ", ")) 57 cm.Message.RecordNetworkHop(cm.Seen[0], mid, cm.Seen[len(cm.Seen)-1]) 58 } 59 60 j, err := cm.Message.JSON() 61 if err != nil { 62 logger.Errorf("Could not JSON encode message '%s': %s", cm.RequestID, err) 63 ectr.Inc() 64 return 65 } 66 67 for _, target := range cm.Targets { 68 if err = nc.PublishRaw(target, []byte(j)); err != nil { 69 logger.Errorf("Could not publish message '%s' to '%s': %s", cm.RequestID, target, err) 70 ectr.Inc() 71 continue 72 } 73 pctr.Inc() 74 } 75 } 76 77 for { 78 var cm chainmessage 79 80 select { 81 case cm = <-self.in: 82 handler(cm) 83 case <-ctx.Done(): 84 logger.Infof("Worker routine %s exiting", self.Name()) 85 return 86 } 87 } 88 }) 89 90 return worker, err 91 }