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  }