github.com/choria-io/go-choria@v0.28.1-0.20240416190746-b3bf9c7d5a45/broker/federation/choria_nats_ingest.go (about)

     1  // Copyright (c) 2017-2022, 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  
    11  	"github.com/choria-io/go-choria/broker/federation/stats"
    12  	"github.com/choria-io/go-choria/inter"
    13  	"github.com/prometheus/client_golang/prometheus"
    14  	log "github.com/sirupsen/logrus"
    15  )
    16  
    17  func NewChoriaNatsIngest(workers int, mode int, capacity int, broker *FederationBroker, logger *log.Entry) (*pooledWorker, error) {
    18  	worker, err := PooledWorkerFactory("choria_nats_ingest", workers, mode, capacity, broker, logger, func(ctx context.Context, self *pooledWorker, i int, logger *log.Entry) {
    19  		defer self.wg.Done()
    20  
    21  		nc, err := self.connection.NewConnector(ctx, self.servers, self.Name(), logger)
    22  		if err != nil {
    23  			logger.Errorf("Could not start NATS connection for worker %d: %s", i, err)
    24  			return
    25  		}
    26  
    27  		var grp, subj string
    28  
    29  		switch self.mode {
    30  		case Federation:
    31  			subj = fmt.Sprintf("choria.federation.%s.federation", self.broker.Name)
    32  			grp = fmt.Sprintf("%s_federation", self.broker.Name)
    33  		case Collective:
    34  			subj = fmt.Sprintf("choria.federation.%s.collective", self.broker.Name)
    35  			grp = fmt.Sprintf("%s_collective", self.broker.Name)
    36  		}
    37  
    38  		natsch, err := nc.ChanQueueSubscribe("ingest", subj, grp, 64)
    39  		if err != nil {
    40  			logger.Errorf("Could not subscribe to %s: %s", subj, err)
    41  			return
    42  		}
    43  
    44  		workeri := fmt.Sprintf("%d", i)
    45  		mname := nameForConnectionMode(mode)
    46  		ctr := stats.ReceivedMsgsCtr.WithLabelValues("nats_ingest", workeri, mname, self.broker.Name, self.broker.identity)
    47  		ectr := stats.ErrorCtr.WithLabelValues("nats_ingest", workeri, mname, self.broker.Name, self.broker.identity)
    48  		timer := stats.ProcessTime.WithLabelValues("nats_ingest", workeri, mname, self.broker.Name, self.broker.identity)
    49  
    50  		handler := func(msg inter.ConnectorMessage) {
    51  			obs := prometheus.NewTimer(timer)
    52  			defer obs.ObserveDuration()
    53  
    54  			message, err := self.choria.NewTransportFromJSON(msg.Data())
    55  			if err != nil {
    56  				logger.Warnf("Could not parse received message into a TransportMessage: %s", err)
    57  				ectr.Inc()
    58  				return
    59  			}
    60  
    61  			reqid, federated := message.FederationRequestID()
    62  			if !federated {
    63  				logger.Warnf("Received a message on %s that was not federated", msg.Subject())
    64  				ectr.Inc()
    65  				return
    66  			}
    67  
    68  			cm := chainmessage{
    69  				Message:   message,
    70  				RequestID: reqid,
    71  				Seen:      []string{nc.ConnectedServer(), fmt.Sprintf("%s:%d", self.Name(), i)},
    72  			}
    73  
    74  			logger.Debugf("Received message %s via %s", reqid, message.SenderID())
    75  
    76  			self.out <- cm
    77  			ctr.Inc()
    78  		}
    79  
    80  		for {
    81  			var msg inter.ConnectorMessage
    82  
    83  			select {
    84  			case msg = <-natsch:
    85  				handler(msg)
    86  
    87  			case <-ctx.Done():
    88  				logger.Infof("Worker routine %s exiting", self.Name())
    89  				return
    90  			}
    91  		}
    92  	})
    93  
    94  	return worker, err
    95  }