github.com/Jeffail/benthos/v3@v3.65.0/lib/input/reader/redis_list.go (about) 1 package reader 2 3 import ( 4 "context" 5 "fmt" 6 "sync" 7 "time" 8 9 bredis "github.com/Jeffail/benthos/v3/internal/impl/redis" 10 "github.com/Jeffail/benthos/v3/lib/log" 11 "github.com/Jeffail/benthos/v3/lib/message" 12 "github.com/Jeffail/benthos/v3/lib/metrics" 13 "github.com/Jeffail/benthos/v3/lib/types" 14 "github.com/go-redis/redis/v7" 15 ) 16 17 //------------------------------------------------------------------------------ 18 19 // RedisListConfig contains configuration fields for the RedisList input type. 20 type RedisListConfig struct { 21 bredis.Config `json:",inline" yaml:",inline"` 22 Key string `json:"key" yaml:"key"` 23 Timeout string `json:"timeout" yaml:"timeout"` 24 } 25 26 // NewRedisListConfig creates a new RedisListConfig with default values. 27 func NewRedisListConfig() RedisListConfig { 28 return RedisListConfig{ 29 Config: bredis.NewConfig(), 30 Key: "benthos_list", 31 Timeout: "5s", 32 } 33 } 34 35 //------------------------------------------------------------------------------ 36 37 // RedisList is an input type that reads Redis List messages. 38 type RedisList struct { 39 client redis.UniversalClient 40 cMut sync.Mutex 41 42 conf RedisListConfig 43 timeout time.Duration 44 45 stats metrics.Type 46 log log.Modular 47 } 48 49 // NewRedisList creates a new RedisList input type. 50 func NewRedisList( 51 conf RedisListConfig, log log.Modular, stats metrics.Type, 52 ) (*RedisList, error) { 53 r := &RedisList{ 54 conf: conf, 55 stats: stats, 56 log: log, 57 } 58 59 if tout := conf.Timeout; len(tout) > 0 { 60 var err error 61 if r.timeout, err = time.ParseDuration(tout); err != nil { 62 return nil, fmt.Errorf("failed to parse timeout string: %v", err) 63 } 64 } 65 66 if _, err := conf.Config.Client(); err != nil { 67 return nil, err 68 } 69 return r, nil 70 } 71 72 //------------------------------------------------------------------------------ 73 74 // Connect establishes a connection to a Redis server. 75 func (r *RedisList) Connect() error { 76 return r.ConnectWithContext(context.Background()) 77 } 78 79 // ConnectWithContext establishes a connection to a Redis server. 80 func (r *RedisList) ConnectWithContext(ctx context.Context) error { 81 r.cMut.Lock() 82 defer r.cMut.Unlock() 83 84 if r.client != nil { 85 return nil 86 } 87 88 client, err := r.conf.Config.Client() 89 if err == nil { 90 _, err = client.Ping().Result() 91 } 92 if err != nil { 93 return err 94 } 95 96 r.log.Infof("Receiving messages from Redis list: %v\n", r.conf.Key) 97 98 r.client = client 99 return nil 100 } 101 102 // Read attempts to pop a message from a Redis list. 103 func (r *RedisList) Read() (types.Message, error) { 104 msg, _, err := r.ReadWithContext(context.Background()) 105 return msg, err 106 } 107 108 // ReadWithContext attempts to pop a message from a Redis list. 109 func (r *RedisList) ReadWithContext(ctx context.Context) (types.Message, AsyncAckFn, error) { 110 var client redis.UniversalClient 111 112 r.cMut.Lock() 113 client = r.client 114 r.cMut.Unlock() 115 116 if client == nil { 117 return nil, nil, types.ErrNotConnected 118 } 119 120 res, err := client.BLPop(r.timeout, r.conf.Key).Result() 121 122 if err != nil && err != redis.Nil { 123 r.disconnect() 124 r.log.Errorf("Error from redis: %v\n", err) 125 return nil, nil, types.ErrNotConnected 126 } 127 128 if len(res) < 2 { 129 return nil, nil, types.ErrTimeout 130 } 131 132 return message.New([][]byte{[]byte(res[1])}), noopAsyncAckFn, nil 133 } 134 135 // Acknowledge is a noop since Redis Lists do not support acknowledgements. 136 func (r *RedisList) Acknowledge(err error) error { 137 return nil 138 } 139 140 // disconnect safely closes a connection to an RedisList server. 141 func (r *RedisList) disconnect() error { 142 r.cMut.Lock() 143 defer r.cMut.Unlock() 144 145 var err error 146 if r.client != nil { 147 err = r.client.Close() 148 r.client = nil 149 } 150 return err 151 } 152 153 // CloseAsync shuts down the RedisList input and stops processing requests. 154 func (r *RedisList) CloseAsync() { 155 r.disconnect() 156 } 157 158 // WaitForClose blocks until the RedisList input has closed down. 159 func (r *RedisList) WaitForClose(timeout time.Duration) error { 160 return nil 161 } 162 163 //------------------------------------------------------------------------------