github.com/Jeffail/benthos/v3@v3.65.0/lib/buffer/none.go (about) 1 package buffer 2 3 import ( 4 "sync/atomic" 5 "time" 6 7 "github.com/Jeffail/benthos/v3/internal/docs" 8 "github.com/Jeffail/benthos/v3/lib/log" 9 "github.com/Jeffail/benthos/v3/lib/metrics" 10 "github.com/Jeffail/benthos/v3/lib/types" 11 ) 12 13 //------------------------------------------------------------------------------ 14 15 func init() { 16 Constructors[TypeNone] = TypeSpec{ 17 constructor: NewEmpty, 18 Summary: ` 19 Do not buffer messages. This is the default and most resilient configuration.`, 20 Description: ` 21 Selecting no buffer means the output layer is directly coupled with the input 22 layer. This is the safest and lowest latency option since acknowledgements from 23 at-least-once protocols can be propagated all the way from the output protocol 24 to the input protocol. 25 26 If the output layer is hit with back pressure it will propagate all the way to 27 the input layer, and further up the data stream. If you need to relieve your 28 pipeline of this back pressure consider using a more robust buffering solution 29 such as Kafka before resorting to alternatives.`, 30 config: docs.FieldComponent().HasType(docs.FieldTypeObject), 31 } 32 } 33 34 //------------------------------------------------------------------------------ 35 36 // Empty is an empty buffer, simply forwards messages on directly. 37 type Empty struct { 38 running int32 39 40 messagesOut chan types.Transaction 41 messagesIn <-chan types.Transaction 42 43 closeChan chan struct{} 44 closed chan struct{} 45 } 46 47 // NewEmpty creates a new buffer interface but doesn't buffer messages. 48 func NewEmpty(config Config, mgr types.Manager, log log.Modular, stats metrics.Type) (Type, error) { 49 e := &Empty{ 50 running: 1, 51 messagesOut: make(chan types.Transaction), 52 closeChan: make(chan struct{}), 53 closed: make(chan struct{}), 54 } 55 return e, nil 56 } 57 58 //------------------------------------------------------------------------------ 59 60 // loop is an internal loop of the empty buffer. 61 func (e *Empty) loop() { 62 defer func() { 63 atomic.StoreInt32(&e.running, 0) 64 65 close(e.messagesOut) 66 close(e.closed) 67 }() 68 69 var open bool 70 for atomic.LoadInt32(&e.running) == 1 { 71 var inT types.Transaction 72 select { 73 case inT, open = <-e.messagesIn: 74 if !open { 75 return 76 } 77 case <-e.closeChan: 78 return 79 } 80 select { 81 case e.messagesOut <- inT: 82 case <-e.closeChan: 83 return 84 } 85 } 86 } 87 88 //------------------------------------------------------------------------------ 89 90 // Consume assigns a messages channel for the output to read. 91 func (e *Empty) Consume(msgs <-chan types.Transaction) error { 92 if e.messagesIn != nil { 93 return types.ErrAlreadyStarted 94 } 95 e.messagesIn = msgs 96 go e.loop() 97 return nil 98 } 99 100 // TransactionChan returns the channel used for consuming messages from this 101 // input. 102 func (e *Empty) TransactionChan() <-chan types.Transaction { 103 return e.messagesOut 104 } 105 106 // ErrorsChan returns the errors channel. 107 func (e *Empty) ErrorsChan() <-chan []error { 108 return nil 109 } 110 111 // StopConsuming instructs the buffer to no longer consume data. 112 func (e *Empty) StopConsuming() { 113 e.CloseAsync() 114 } 115 116 // CloseAsync shuts down the StackBuffer output and stops processing messages. 117 func (e *Empty) CloseAsync() { 118 if atomic.CompareAndSwapInt32(&e.running, 1, 0) { 119 close(e.closeChan) 120 } 121 } 122 123 // WaitForClose blocks until the StackBuffer output has closed down. 124 func (e *Empty) WaitForClose(timeout time.Duration) error { 125 select { 126 case <-e.closed: 127 case <-time.After(timeout): 128 return types.ErrTimeout 129 } 130 return nil 131 } 132 133 //------------------------------------------------------------------------------