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

     1  package generic
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	fmt "fmt"
     7  	"time"
     8  
     9  	"go.uber.org/zap"
    10  	"google.golang.org/grpc"
    11  	"google.golang.org/grpc/connectivity"
    12  	"google.golang.org/grpc/credentials/insecure"
    13  	"google.golang.org/grpc/metadata"
    14  
    15  	"github.com/argoproj/argo-events/common"
    16  	"github.com/argoproj/argo-events/common/logging"
    17  	eventsourcecommon "github.com/argoproj/argo-events/eventsources/common"
    18  	"github.com/argoproj/argo-events/eventsources/sources"
    19  	metrics "github.com/argoproj/argo-events/metrics"
    20  	apicommon "github.com/argoproj/argo-events/pkg/apis/common"
    21  	"github.com/argoproj/argo-events/pkg/apis/events"
    22  	"github.com/argoproj/argo-events/pkg/apis/eventsource/v1alpha1"
    23  )
    24  
    25  // EventListener implements Eventing for generic event source
    26  type EventListener struct {
    27  	EventSourceName    string
    28  	EventName          string
    29  	GenericEventSource v1alpha1.GenericEventSource
    30  	Metrics            *metrics.Metrics
    31  
    32  	conn *grpc.ClientConn
    33  }
    34  
    35  // GetEventSourceName returns name of event source
    36  func (el *EventListener) GetEventSourceName() string {
    37  	return el.EventSourceName
    38  }
    39  
    40  // GetEventName returns name of event
    41  func (el *EventListener) GetEventName() string {
    42  	return el.EventName
    43  }
    44  
    45  // GetEventSourceType return type of event server
    46  func (el *EventListener) GetEventSourceType() apicommon.EventSourceType {
    47  	return apicommon.GenericEvent
    48  }
    49  
    50  // StartListening listens to generic events
    51  func (el *EventListener) StartListening(ctx context.Context, dispatch func([]byte, ...eventsourcecommon.Option) error) error {
    52  	logger := logging.FromContext(ctx).
    53  		With(zap.String(logging.LabelEventSourceType, string(el.GetEventSourceType())),
    54  			zap.String(logging.LabelEventName, el.GetEventName()),
    55  			zap.String("url", el.GenericEventSource.URL))
    56  	logger.Info("started processing the generic event source...")
    57  	defer sources.Recover(el.GetEventName())
    58  
    59  	logger.Info("connecting to eventsource server in 5 seconds...")
    60  	ticker := time.NewTicker(5 * time.Second)
    61  	defer ticker.Stop()
    62  	for {
    63  		select {
    64  		case <-ctx.Done():
    65  			logger.Info("closing client connection and exiting eventsource...")
    66  			if el.conn != nil && (el.conn.GetState() == connectivity.Ready || el.conn.GetState() == connectivity.Connecting) {
    67  				el.conn.Close()
    68  			}
    69  			return nil
    70  		case <-ticker.C:
    71  			if el.conn == nil || el.conn.GetState() == connectivity.Shutdown || el.conn.GetState() == connectivity.TransientFailure {
    72  				logger.Info("dialing eventsource server...")
    73  				eventStream, err := el.connect()
    74  				if err != nil {
    75  					logger.Errorw("failed to connect eventsource server, reconnecting in 5 seconds...", zap.Error(err))
    76  					continue
    77  				}
    78  				logger.Info("connected to eventsource server successfully, started event stream...")
    79  				for {
    80  					event, err := eventStream.Recv()
    81  					if err != nil {
    82  						logger.Errorw("failed to receive events from the event stream, reconnecting in 5 seconds...", zap.Error(err))
    83  						// close the connection and retry in next cycle.
    84  						el.conn.Close()
    85  						break
    86  					}
    87  					if err := el.handleOne(event, dispatch, logger); err != nil {
    88  						logger.Errorw("failed to process a Generics event", zap.Error(err))
    89  						el.Metrics.EventProcessingFailed(el.GetEventSourceName(), el.GetEventName())
    90  					}
    91  				}
    92  			}
    93  		}
    94  	}
    95  }
    96  
    97  func (el *EventListener) handleOne(event *Event, dispatch func([]byte, ...eventsourcecommon.Option) error, logger *zap.SugaredLogger) error {
    98  	defer func(start time.Time) {
    99  		el.Metrics.EventProcessingDuration(el.GetEventSourceName(), el.GetEventName(), float64(time.Since(start)/time.Millisecond))
   100  	}(time.Now())
   101  
   102  	logger.Info("received an event from server")
   103  	eventData := &events.GenericEventData{
   104  		Metadata: el.GenericEventSource.Metadata,
   105  	}
   106  	if el.GenericEventSource.JSONBody {
   107  		eventData.Body = (*json.RawMessage)(&event.Payload)
   108  	} else {
   109  		eventData.Body = event.Payload
   110  	}
   111  	eventBytes, err := json.Marshal(eventData)
   112  	if err != nil {
   113  		return fmt.Errorf("failed to marshal the event data, %w", err)
   114  	}
   115  	logger.Info("dispatching event...")
   116  	if err := dispatch(eventBytes); err != nil {
   117  		return fmt.Errorf("failed to dispatch a Generic event, %w", err)
   118  	}
   119  	return nil
   120  }
   121  
   122  func (el *EventListener) connect() (Eventing_StartEventSourceClient, error) {
   123  	var opt []grpc.DialOption
   124  	opt = append(opt, grpc.WithBlock())
   125  	if el.GenericEventSource.Insecure {
   126  		opt = append(opt, grpc.WithTransportCredentials(insecure.NewCredentials()))
   127  	}
   128  	conn, err := grpc.DialContext(context.Background(), el.GenericEventSource.URL, opt...)
   129  	if err != nil {
   130  		return nil, err
   131  	}
   132  	el.conn = conn
   133  	client := NewEventingClient(el.conn)
   134  	ctx := context.Background()
   135  	if el.GenericEventSource.AuthSecret != nil {
   136  		token, err := common.GetSecretFromVolume(el.GenericEventSource.AuthSecret)
   137  		if err != nil {
   138  			return nil, err
   139  		}
   140  		auth := fmt.Sprintf("Bearer %s", token)
   141  		ctx = metadata.NewOutgoingContext(ctx, metadata.Pairs("authorization", auth))
   142  	}
   143  	return client.StartEventSource(ctx, &EventSource{
   144  		Name:   el.GetEventName(),
   145  		Config: []byte(el.GenericEventSource.Config),
   146  	})
   147  }