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 }