github.com/Jeffail/benthos/v3@v3.65.0/internal/batch/error.go (about)

     1  // Package batch contains internal utilities for interacting with message
     2  // batches.
     3  package batch
     4  
     5  import (
     6  	"errors"
     7  
     8  	"github.com/Jeffail/benthos/v3/lib/types"
     9  )
    10  
    11  // Error is an error type that also allows storing granular errors for each
    12  // message of a batch.
    13  type Error struct {
    14  	err        error
    15  	source     types.Message
    16  	partErrors map[int]error
    17  }
    18  
    19  // NewError creates a new batch-wide error, where it's possible to add granular
    20  // errors for individual messages of the batch.
    21  func NewError(msg types.Message, err error) *Error {
    22  	if berr, ok := err.(*Error); ok {
    23  		err = berr.Unwrap()
    24  	}
    25  	return &Error{
    26  		err:    err,
    27  		source: msg,
    28  	}
    29  }
    30  
    31  // Failed stores an error state for a particular message of a batch. Returns a
    32  // pointer to the underlying error, allowing with method to be chained.
    33  //
    34  // If Failed is not called then all messages are assumed to have failed. If it
    35  // is called at least once then all message indexes that aren't explicitly
    36  // failed are assumed to have been processed successfully.
    37  func (e *Error) Failed(i int, err error) *Error {
    38  	if e.partErrors == nil {
    39  		e.partErrors = make(map[int]error)
    40  	}
    41  	e.partErrors[i] = err
    42  	return e
    43  }
    44  
    45  // IndexedErrors returns the number of indexed errors that have been registered
    46  // for the batch.
    47  func (e *Error) IndexedErrors() int {
    48  	return len(e.partErrors)
    49  }
    50  
    51  // WalkableError is an interface implemented by batch errors that allows you to
    52  // walk the messages of the batch and dig into the individual errors.
    53  type WalkableError interface {
    54  	WalkParts(fn func(int, types.Part, error) bool)
    55  	IndexedErrors() int
    56  	error
    57  }
    58  
    59  // WalkParts applies a closure to each message that was part of the request that
    60  // caused this error. The closure is provided the message part index, a pointer
    61  // to the part, and its individual error, which may be nil if the message itself
    62  // was processed successfully. The closure returns a bool which indicates
    63  // whether the iteration should be continued.
    64  func (e *Error) WalkParts(fn func(int, types.Part, error) bool) {
    65  	e.source.Iter(func(i int, p types.Part) error {
    66  		var err error
    67  		if e.partErrors == nil {
    68  			err = e.err
    69  		} else {
    70  			err = e.partErrors[i]
    71  		}
    72  		if !fn(i, p, err) {
    73  			return errors.New("stop")
    74  		}
    75  		return nil
    76  	})
    77  }
    78  
    79  // Error implements the common error interface.
    80  func (e *Error) Error() string {
    81  	return e.err.Error()
    82  }
    83  
    84  // Unwrap returns the underlying common error.
    85  func (e *Error) Unwrap() error {
    86  	return e.err
    87  }