github.com/argoproj/argo-events@v1.9.1/eventbus/kafka/sensor/trigger_handler.go (about) 1 package kafka 2 3 import ( 4 "time" 5 6 "github.com/Knetic/govaluate" 7 "github.com/argoproj/argo-events/eventbus/common" 8 "github.com/argoproj/argo-events/eventbus/kafka/base" 9 cloudevents "github.com/cloudevents/sdk-go/v2" 10 "go.uber.org/zap" 11 ) 12 13 type KafkaTriggerHandler interface { 14 common.TriggerConnection 15 Name() string 16 Ready() bool 17 Reset() 18 OneAndDone() bool 19 DependsOn(*cloudevents.Event) (string, bool) 20 Transform(string, *cloudevents.Event) (*cloudevents.Event, error) 21 Filter(string, *cloudevents.Event) bool 22 Update(event *cloudevents.Event, partition int32, offset int64, timestamp time.Time) ([]*cloudevents.Event, error) 23 Offset(int32, int64) int64 24 Action([]*cloudevents.Event) func() 25 } 26 27 func (c *KafkaTriggerConnection) Name() string { 28 return c.triggerName 29 } 30 31 func (c *KafkaTriggerConnection) Ready() bool { 32 // cannot process events until the subscribe function has been 33 // called, which is when these functions are set 34 return c.transform != nil && c.filter != nil && c.action != nil 35 } 36 37 func (c *KafkaTriggerConnection) DependsOn(event *cloudevents.Event) (string, bool) { 38 if dep, ok := c.dependencies[base.EventKey(event.Source(), event.Subject())]; ok { 39 return dep.Name, true 40 } 41 42 return "", false 43 } 44 45 func (c *KafkaTriggerConnection) OneAndDone() bool { 46 for _, token := range c.depExpression.Tokens() { 47 if token.Kind == govaluate.LOGICALOP && token.Value == "&&" { 48 return false 49 } 50 } 51 52 return true 53 } 54 55 func (c *KafkaTriggerConnection) Transform(depName string, event *cloudevents.Event) (*cloudevents.Event, error) { 56 return c.transform(depName, *event) 57 } 58 59 func (c *KafkaTriggerConnection) Filter(depName string, event *cloudevents.Event) bool { 60 return c.filter(depName, *event) 61 } 62 63 func (c *KafkaTriggerConnection) Update(event *cloudevents.Event, partition int32, offset int64, timestamp time.Time) ([]*cloudevents.Event, error) { 64 eventWithMetadata := &eventWithMetadata{ 65 Event: event, 66 partition: partition, 67 offset: offset, 68 timestamp: timestamp, 69 } 70 71 // remove previous events with same source and subject and remove 72 // all events older than last condition reset time 73 i := 0 74 for _, event := range c.events { 75 if !event.Same(eventWithMetadata) && event.After(c.lastResetTime) { 76 c.events[i] = event 77 i++ 78 } 79 } 80 for j := i; j < len(c.events); j++ { 81 c.events[j] = nil // avoid memory leak 82 } 83 c.events = append(c.events[:i], eventWithMetadata) 84 85 satisfied, err := c.satisfied() 86 if err != nil { 87 return nil, err 88 } 89 90 // if satisfied, publish a message to the action topic containing 91 // all events and reset the trigger 92 var events []*cloudevents.Event 93 if satisfied == true { 94 defer c.Reset() 95 for _, event := range c.events { 96 events = append(events, event.Event) 97 } 98 } 99 100 return events, nil 101 } 102 103 func (c *KafkaTriggerConnection) Offset(partition int32, offset int64) int64 { 104 for _, event := range c.events { 105 if partition == event.partition && offset > event.offset { 106 offset = event.offset 107 } 108 } 109 110 return offset 111 } 112 113 func (c *KafkaTriggerConnection) Action(events []*cloudevents.Event) func() { 114 eventMap := map[string]cloudevents.Event{} 115 for _, event := range events { 116 if depName, ok := c.DependsOn(event); ok { 117 eventMap[depName] = *event 118 } 119 } 120 121 // If at least once is specified, we must call the action 122 // function before committing a transaction, otherwise the 123 // function must be called after. To call after we return a 124 // function. 125 var f func() 126 if c.atLeastOnce { 127 c.action(eventMap) 128 } else { 129 f = func() { c.action(eventMap) } 130 } 131 132 return f 133 } 134 135 func (c *KafkaTriggerConnection) satisfied() (interface{}, error) { 136 parameters := Parameters{} 137 for _, event := range c.events { 138 if depName, ok := c.DependsOn(event.Event); ok { 139 parameters[depName] = true 140 } 141 } 142 143 c.Logger.Infow("Evaluating", zap.String("expr", c.depExpression.String()), zap.Any("parameters", parameters)) 144 145 return c.depExpression.Eval(parameters) 146 } 147 148 func (c *KafkaTriggerConnection) Reset() { 149 c.events = nil 150 } 151 152 type Parameters map[string]bool 153 154 func (p Parameters) Get(name string) (interface{}, error) { 155 return p[name], nil 156 }