github.com/Jeffail/benthos/v3@v3.65.0/internal/component/processor/processor_v2.go (about) 1 package processor 2 3 import ( 4 "context" 5 "time" 6 7 "github.com/Jeffail/benthos/v3/internal/shutdown" 8 "github.com/Jeffail/benthos/v3/internal/tracing" 9 "github.com/Jeffail/benthos/v3/lib/message" 10 "github.com/Jeffail/benthos/v3/lib/metrics" 11 "github.com/Jeffail/benthos/v3/lib/processor" 12 "github.com/Jeffail/benthos/v3/lib/response" 13 "github.com/Jeffail/benthos/v3/lib/types" 14 ) 15 16 // V2 is a simpler interface to implement than types.Processor. 17 type V2 interface { 18 // Process a message into one or more resulting messages, or return an error 19 // if the message could not be processed. If zero messages are returned and 20 // the error is nil then the message is filtered. 21 Process(ctx context.Context, p types.Part) ([]types.Part, error) 22 23 // Close the component, blocks until either the underlying resources are 24 // cleaned up or the context is cancelled. Returns an error if the context 25 // is cancelled. 26 Close(ctx context.Context) error 27 } 28 29 // V2Batched is a simpler interface to implement than types.Processor and allows 30 // batch-wide processing. 31 type V2Batched interface { 32 // Process a batch of messages into one or more resulting batches, or return 33 // an error if the entire batch could not be processed. If zero messages are 34 // returned and the error is nil then all messages are filtered. 35 ProcessBatch(ctx context.Context, p []types.Part) ([][]types.Part, error) 36 37 // Close the component, blocks until either the underlying resources are 38 // cleaned up or the context is cancelled. Returns an error if the context 39 // is cancelled. 40 Close(ctx context.Context) error 41 } 42 43 //------------------------------------------------------------------------------ 44 45 // Implements types.Processor 46 type v2ToV1Processor struct { 47 typeStr string 48 p V2 49 sig *shutdown.Signaller 50 51 mCount metrics.StatCounter 52 mDropped metrics.StatCounter 53 mErr metrics.StatCounter 54 mSent metrics.StatCounter 55 } 56 57 // NewV2ToV1Processor wraps a processor.V2 with a struct that implements 58 // types.Processor. 59 func NewV2ToV1Processor(typeStr string, p V2, stats metrics.Type) types.Processor { 60 return &v2ToV1Processor{ 61 typeStr: typeStr, p: p, sig: shutdown.NewSignaller(), 62 63 mCount: stats.GetCounter("count"), 64 mErr: stats.GetCounter("error"), 65 mSent: stats.GetCounter("sent"), 66 mDropped: stats.GetCounter("dropped"), 67 } 68 } 69 70 func (a *v2ToV1Processor) ProcessMessage(msg types.Message) ([]types.Message, types.Response) { 71 a.mCount.Incr(1) 72 73 newParts := make([]types.Part, 0, msg.Len()) 74 75 msg.Iter(func(i int, part types.Part) error { 76 span := tracing.CreateChildSpan(a.typeStr, part) 77 78 nextParts, err := a.p.Process(context.Background(), part) 79 if err != nil { 80 newPart := part.Copy() 81 a.mErr.Incr(1) 82 processor.FlagErr(newPart, err) 83 span.SetTag("error", true) 84 span.LogKV( 85 "event", "error", 86 "type", err.Error(), 87 ) 88 nextParts = append(nextParts, newPart) 89 } 90 91 span.Finish() 92 if len(nextParts) > 0 { 93 newParts = append(newParts, nextParts...) 94 } else { 95 a.mDropped.Incr(1) 96 } 97 return nil 98 }) 99 100 if len(newParts) == 0 { 101 return nil, response.NewAck() 102 } 103 104 newMsg := message.New(nil) 105 newMsg.SetAll(newParts) 106 107 a.mSent.Incr(int64(newMsg.Len())) 108 return []types.Message{newMsg}, nil 109 } 110 111 func (a *v2ToV1Processor) CloseAsync() { 112 go func() { 113 if err := a.p.Close(context.Background()); err == nil { 114 a.sig.ShutdownComplete() 115 } 116 }() 117 } 118 119 func (a *v2ToV1Processor) WaitForClose(tout time.Duration) error { 120 select { 121 case <-a.sig.HasClosedChan(): 122 case <-time.After(tout): 123 return types.ErrTimeout 124 } 125 return nil 126 } 127 128 //------------------------------------------------------------------------------ 129 130 // Implements types.Processor 131 type v2BatchedToV1Processor struct { 132 typeStr string 133 p V2Batched 134 sig *shutdown.Signaller 135 136 mCount metrics.StatCounter 137 mErr metrics.StatCounter 138 mSent metrics.StatCounter 139 } 140 141 // NewV2BatchedToV1Processor wraps a processor.V2Batched with a struct that 142 // implements types.Processor. 143 func NewV2BatchedToV1Processor(typeStr string, p V2Batched, stats metrics.Type) types.Processor { 144 return &v2BatchedToV1Processor{ 145 typeStr: typeStr, p: p, sig: shutdown.NewSignaller(), 146 147 mCount: stats.GetCounter("count"), 148 mErr: stats.GetCounter("error"), 149 mSent: stats.GetCounter("sent"), 150 } 151 } 152 153 func (a *v2BatchedToV1Processor) ProcessMessage(msg types.Message) ([]types.Message, types.Response) { 154 a.mCount.Incr(1) 155 156 newMsg, spans := tracing.WithChildSpans(a.typeStr, msg) 157 parts := make([]types.Part, newMsg.Len()) 158 newMsg.Iter(func(i int, part types.Part) error { 159 parts[i] = part 160 return nil 161 }) 162 163 var outputBatches []types.Message 164 165 batches, err := a.p.ProcessBatch(context.Background(), parts) 166 if err != nil { 167 a.mErr.Incr(1) 168 for i, p := range parts { 169 parts[i] = p.Copy() 170 processor.FlagErr(parts[i], err) 171 } 172 for _, s := range spans { 173 s.SetTag("error", true) 174 s.LogKV( 175 "event", "error", 176 "type", err.Error(), 177 ) 178 } 179 newMsg.SetAll(parts) 180 outputBatches = append(outputBatches, newMsg) 181 } else { 182 for _, batch := range batches { 183 a.mSent.Incr(int64(len(batch))) 184 nextMsg := message.New(nil) 185 nextMsg.SetAll(batch) 186 outputBatches = append(outputBatches, nextMsg) 187 } 188 } 189 190 tracing.FinishSpans(newMsg) 191 192 if len(outputBatches) == 0 { 193 return nil, response.NewAck() 194 } 195 return outputBatches, nil 196 } 197 198 func (a *v2BatchedToV1Processor) CloseAsync() { 199 go func() { 200 if err := a.p.Close(context.Background()); err == nil { 201 a.sig.ShutdownComplete() 202 } 203 }() 204 } 205 206 func (a *v2BatchedToV1Processor) WaitForClose(tout time.Duration) error { 207 select { 208 case <-a.sig.HasClosedChan(): 209 case <-time.After(tout): 210 return types.ErrTimeout 211 } 212 return nil 213 }