github.com/argoproj/argo-events@v1.9.1/eventsources/sources/azureservicebus/start.go (about)

     1  package azureservicebus
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"time"
     7  
     8  	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
     9  	servicebus "github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus"
    10  	"go.uber.org/zap"
    11  
    12  	"github.com/argoproj/argo-events/common"
    13  	"github.com/argoproj/argo-events/common/logging"
    14  	eventsourcecommon "github.com/argoproj/argo-events/eventsources/common"
    15  	"github.com/argoproj/argo-events/eventsources/sources"
    16  	metrics "github.com/argoproj/argo-events/metrics"
    17  	apicommon "github.com/argoproj/argo-events/pkg/apis/common"
    18  	"github.com/argoproj/argo-events/pkg/apis/events"
    19  	"github.com/argoproj/argo-events/pkg/apis/eventsource/v1alpha1"
    20  )
    21  
    22  // EventListener implements Eventing for azure events hub event source
    23  type EventListener struct {
    24  	EventSourceName            string
    25  	EventName                  string
    26  	AzureServiceBusEventSource v1alpha1.AzureServiceBusEventSource
    27  	Metrics                    *metrics.Metrics
    28  }
    29  
    30  // GetEventSourceName returns name of event source
    31  func (el *EventListener) GetEventSourceName() string {
    32  	return el.EventSourceName
    33  }
    34  
    35  // GetEventName returns name of event
    36  func (el *EventListener) GetEventName() string {
    37  	return el.EventName
    38  }
    39  
    40  // GetEventSourceType return type of event server
    41  func (el *EventListener) GetEventSourceType() apicommon.EventSourceType {
    42  	return apicommon.AzureServiceBus
    43  }
    44  
    45  type ReceiverType string
    46  
    47  const (
    48  	ReceiverTypeQueue        ReceiverType = "queue"
    49  	ReceiverTypeSubscription ReceiverType = "subscription"
    50  )
    51  
    52  // StartListening starts listening events
    53  func (el *EventListener) StartListening(ctx context.Context, dispatch func([]byte, ...eventsourcecommon.Option) error) error {
    54  	log := logging.FromContext(ctx).
    55  		With(logging.LabelEventSourceType, el.GetEventSourceType(), logging.LabelEventName, el.GetEventName())
    56  
    57  	log.Info("started processing the Azure Service Bus event source...")
    58  	defer sources.Recover(el.GetEventName())
    59  
    60  	servicebusEventSource := &el.AzureServiceBusEventSource
    61  	clientOptions := servicebus.ClientOptions{}
    62  	if servicebusEventSource.TLS != nil {
    63  		tlsConfig, err := common.GetTLSConfig(servicebusEventSource.TLS)
    64  		if err != nil {
    65  			log.Errorw("failed to get the tls configuration", zap.Error(err))
    66  			return err
    67  		}
    68  		clientOptions.TLSConfig = tlsConfig
    69  	}
    70  	var client *servicebus.Client
    71  	if servicebusEventSource.ConnectionString != nil {
    72  		log.Info("connecting to the service bus using connection string...")
    73  		connStr, err := common.GetSecretFromVolume(servicebusEventSource.ConnectionString)
    74  		if err != nil {
    75  			log.With("connection-string", servicebusEventSource.ConnectionString.Name).Errorw("failed to retrieve connection string from secret", zap.Error(err))
    76  			return err
    77  		}
    78  		client, err = servicebus.NewClientFromConnectionString(connStr, &clientOptions)
    79  		if err != nil {
    80  			log.Errorw("failed to create a service bus client", zap.Error(err))
    81  			return err
    82  		}
    83  	} else {
    84  		log.Info("connecting to azure queue storage with AAD credentials...")
    85  		cred, err := azidentity.NewDefaultAzureCredential(nil)
    86  		if err != nil {
    87  			log.Errorw("failed to create DefaultAzureCredential", zap.Error(err))
    88  			return err
    89  		}
    90  		client, err = servicebus.NewClient(servicebusEventSource.FullyQualifiedNamespace, cred, &clientOptions)
    91  		if err != nil {
    92  			log.Errorw("failed to create a service bus client", zap.Error(err))
    93  			return err
    94  		}
    95  	}
    96  
    97  	var receiver *servicebus.Receiver
    98  	var receiverType ReceiverType
    99  	var err error
   100  
   101  	if servicebusEventSource.QueueName != "" {
   102  		log.Info("creating a queue receiver...")
   103  		receiverType = ReceiverTypeQueue
   104  		receiver, err = client.NewReceiverForQueue(servicebusEventSource.QueueName, &servicebus.ReceiverOptions{
   105  			ReceiveMode: servicebus.ReceiveModeReceiveAndDelete,
   106  		})
   107  	} else {
   108  		log.Info("creating a subscription receiver...")
   109  		receiverType = ReceiverTypeSubscription
   110  		receiver, err = client.NewReceiverForSubscription(servicebusEventSource.TopicName, servicebusEventSource.SubscriptionName, &servicebus.ReceiverOptions{
   111  			ReceiveMode: servicebus.ReceiveModeReceiveAndDelete,
   112  		})
   113  	}
   114  	if err != nil {
   115  		if receiverType == ReceiverTypeQueue {
   116  			log.With("queue", servicebusEventSource.QueueName).Errorw("failed to create a queue receiver", zap.Error(err))
   117  		} else {
   118  			log.With("topic", servicebusEventSource.TopicName, "subscription", servicebusEventSource.SubscriptionName).Errorw("failed to create a receiver for subscription", zap.Error(err))
   119  		}
   120  		return err
   121  	}
   122  
   123  	if servicebusEventSource.JSONBody {
   124  		log.Info("assuming all events have a json body...")
   125  	}
   126  
   127  	for {
   128  		select {
   129  		case <-ctx.Done():
   130  			log.Info("context has been cancelled, stopping the Azure Service Bus event source...")
   131  			if err := receiver.Close(ctx); err != nil {
   132  				log.Errorw("failed to close the receiver", zap.Error(err))
   133  				return err
   134  			}
   135  			return nil
   136  		default:
   137  			messages, err := receiver.ReceiveMessages(ctx, 1, nil)
   138  			if err != nil {
   139  				log.Errorw("failed to receive messages", zap.Error(err))
   140  				continue
   141  			}
   142  
   143  			for _, message := range messages {
   144  				if err := el.handleOne(servicebusEventSource, message, dispatch, log); err != nil {
   145  					if receiverType == ReceiverTypeQueue {
   146  						log.With("queue", servicebusEventSource.QueueName, "message_id", message.MessageID).Errorw("failed to process Azure Service Bus message", zap.Error(err))
   147  					} else {
   148  						log.With("topic", servicebusEventSource.TopicName, "subscription", servicebusEventSource.SubscriptionName, "message_id", message.MessageID).Errorw("failed to process Azure Service Bus message", zap.Error(err))
   149  					}
   150  					el.Metrics.EventProcessingFailed(el.GetEventSourceName(), el.GetEventName())
   151  					continue
   152  				}
   153  			}
   154  		}
   155  	}
   156  }
   157  
   158  func (el *EventListener) handleOne(servicebusEventSource *v1alpha1.AzureServiceBusEventSource, message *servicebus.ReceivedMessage, dispatch func([]byte, ...eventsourcecommon.Option) error, log *zap.SugaredLogger) error {
   159  	defer func(start time.Time) {
   160  		el.Metrics.EventProcessingDuration(el.GetEventSourceName(), el.GetEventName(), float64(time.Since(start)/time.Millisecond))
   161  	}(time.Now())
   162  
   163  	log.Infow("received the message", zap.Any("message_id", message.MessageID))
   164  	eventData := &events.AzureServiceBusEventData{
   165  		ApplicationProperties: message.ApplicationProperties,
   166  		ContentType:           message.ContentType,
   167  		CorrelationID:         message.CorrelationID,
   168  		EnqueuedTime:          message.EnqueuedTime,
   169  		MessageID:             message.MessageID,
   170  		ReplyTo:               message.ReplyTo,
   171  		SequenceNumber:        message.SequenceNumber,
   172  		Subject:               message.Subject,
   173  		Metadata:              servicebusEventSource.Metadata,
   174  	}
   175  
   176  	if servicebusEventSource.JSONBody {
   177  		eventData.Body = (*json.RawMessage)(&message.Body)
   178  	} else {
   179  		eventData.Body = message.Body
   180  	}
   181  
   182  	eventBytes, err := json.Marshal(eventData)
   183  	if err != nil {
   184  		log.With("event_source", el.GetEventSourceName(), "event", el.GetEventName(), "message_id", message.MessageID).Errorw("failed to marshal the event data", zap.Error(err))
   185  		return err
   186  	}
   187  
   188  	log.Info("dispatching the event to eventbus...")
   189  	if err = dispatch(eventBytes); err != nil {
   190  		log.With("event_source", el.GetEventSourceName(), "event", el.GetEventName(), "message_id", message.MessageID).Errorw("failed to dispatch the event", zap.Error(err))
   191  		return err
   192  	}
   193  
   194  	return nil
   195  }