github.com/Jeffail/benthos/v3@v3.65.0/lib/output/reject.go (about) 1 package output 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "time" 8 9 "github.com/Jeffail/benthos/v3/internal/bloblang/field" 10 "github.com/Jeffail/benthos/v3/internal/docs" 11 "github.com/Jeffail/benthos/v3/internal/interop" 12 "github.com/Jeffail/benthos/v3/lib/log" 13 "github.com/Jeffail/benthos/v3/lib/metrics" 14 "github.com/Jeffail/benthos/v3/lib/types" 15 ) 16 17 //------------------------------------------------------------------------------ 18 19 func init() { 20 Constructors[TypeReject] = TypeSpec{ 21 constructor: fromSimpleConstructor(func(conf Config, mgr types.Manager, log log.Modular, stats metrics.Type) (Type, error) { 22 f, err := newRejectWriter(mgr, string(conf.Reject)) 23 if err != nil { 24 return nil, err 25 } 26 return NewAsyncWriter(TypeReject, 1, f, log, stats) 27 }), 28 Status: docs.StatusStable, 29 Summary: ` 30 Rejects all messages, treating them as though the output destination failed to publish them.`, 31 Description: ` 32 The routing of messages after this output depends on the type of input it came from. For inputs that support propagating nacks upstream such as AMQP or NATS the message will be nacked. However, for inputs that are sequential such as files or Kafka the messages will simply be reprocessed from scratch. 33 34 If you're still scratching your head as to when this output could be useful check out [the examples below](#examples).`, 35 Categories: []Category{ 36 CategoryUtility, 37 }, 38 Examples: []docs.AnnotatedExample{ 39 { 40 Title: "Rejecting Failed Messages", 41 Summary: ` 42 This input is particularly useful for routing messages that have failed during processing, where instead of routing them to some sort of dead letter queue we wish to push the error upstream. We can do this with a switch broker:`, 43 Config: ` 44 output: 45 switch: 46 retry_until_success: false 47 cases: 48 - check: '!errored()' 49 output: 50 amqp_1: 51 url: amqps://guest:guest@localhost:5672/ 52 target_address: queue:/the_foos 53 54 - output: 55 reject: "processing failed due to: ${! error() }" 56 `, 57 }, 58 }, 59 config: docs.FieldComponent().HasType(docs.FieldTypeString).HasDefault(""), 60 } 61 } 62 63 //------------------------------------------------------------------------------ 64 65 // RejectConfig contains configuration fields for the file based output type. 66 type RejectConfig string 67 68 // NewRejectConfig creates a new RejectConfig with default values. 69 func NewRejectConfig() RejectConfig { 70 return RejectConfig("") 71 } 72 73 type rejectWriter struct { 74 errExpr *field.Expression 75 } 76 77 func newRejectWriter(mgr types.Manager, errorString string) (*rejectWriter, error) { 78 if errorString == "" { 79 return nil, errors.New("an error message must be provided in order to provide context for the rejection") 80 } 81 errExpr, err := interop.NewBloblangField(mgr, errorString) 82 if err != nil { 83 return nil, fmt.Errorf("failed to parse error expression: %w", err) 84 } 85 return &rejectWriter{errExpr}, nil 86 } 87 88 func (w *rejectWriter) ConnectWithContext(ctx context.Context) error { 89 return nil 90 } 91 92 func (w *rejectWriter) WriteWithContext(ctx context.Context, msg types.Message) error { 93 errStr := w.errExpr.String(0, msg) 94 return errors.New(errStr) 95 } 96 97 func (w *rejectWriter) CloseAsync() { 98 } 99 100 func (w *rejectWriter) WaitForClose(timeout time.Duration) error { 101 return nil 102 }