Skip to content

Commit 226bb97

Browse files
author
Juuso Mäyränen
committed
Merge remote-tracking branch 'origin/master' into list-pattern-input
2 parents d52e87d + 71d3ee5 commit 226bb97

File tree

8 files changed

+298
-224
lines changed

8 files changed

+298
-224
lines changed

.ci/docker-compose.override.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
version: '3'
2+
3+
services:
4+
logstash:
5+
network_mode: host

.ci/run.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/bin/bash
2+
# This is intended to be run inside the docker container as the command of the docker-compose.
3+
4+
env
5+
6+
set -ex
7+
8+
jruby -rbundler/setup -S rspec -fd
9+
10+
jruby -rbundler/setup -S rspec -fd --tag redis

.travis.yml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,13 @@
11
import:
2-
- logstash-plugins/.ci:travis/[email protected]
2+
- logstash-plugins/.ci:travis/[email protected]
3+
4+
addons:
5+
apt:
6+
sources:
7+
- sourceline: 'ppa:chris-lea/redis-server'
8+
packages:
9+
- redis-server
10+
11+
before_install:
12+
- sudo service redis-server stop
13+
- sudo service redis-server start --bind 0.0.0.0

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
## 3.7.0
2+
- Fix: better (Redis) exception handling [#89](https://github.com/logstash-plugins/logstash-input-redis/pull/89)
3+
- Test: start running integration specs on CI
4+
5+
## 3.6.1
6+
- Fix: resolve crash when commands_map is set [#86](https://github.com/logstash-plugins/logstash-input-redis/pull/86)
7+
18
## 3.6.0
29
- Remove ruby pipeline dependency. Starting from Logstash 8, Ruby execution engine is not available. All pipelines should use Java pipeline [#84](https://github.com/logstash-plugins/logstash-input-redis/pull/84)
310

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Logstash Plugin
22

33
Travis Build
4-
[![Travis Build Status](https://travis-ci.org/logstash-plugins/logstash-input-redis.svg)](https://travis-ci.org/logstash-plugins/logstash-input-redis)
4+
[![Travis Build Status](https://travis-ci.com/logstash-plugins/logstash-input-redis.svg)](https://travis-ci.com/logstash-plugins/logstash-input-redis)
55

66
This is a plugin for [Logstash](https://github.com/elastic/logstash).
77

lib/logstash/inputs/redis.rb

Lines changed: 66 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -77,22 +77,6 @@ module LogStash module Inputs class Redis < LogStash::Inputs::Threadable
7777
config :pattern_list_threadpool_sleep, :validate => :number, :default => 0.2
7878

7979
public
80-
# public API
81-
# use to store a proc that can provide a Redis instance or mock
82-
def add_external_redis_builder(builder) #callable
83-
@redis_builder = builder
84-
self
85-
end
86-
87-
# use to apply an instance directly and bypass the builder
88-
def use_redis(instance)
89-
@redis = instance
90-
self
91-
end
92-
93-
def new_redis_instance
94-
@redis_builder.call
95-
end
9680

9781
def init_threadpool
9882
@threadpool ||= Concurrent::ThreadPoolExecutor.new(
@@ -106,8 +90,6 @@ def init_threadpool
10690
def register
10791
@redis_url = @path.nil? ? "redis://#{@password}@#{@host}:#{@port}/#{@db}" : "#{@password}@#{@path}/#{@db}"
10892

109-
@redis_builder ||= method(:internal_redis_builder)
110-
11193
# just switch on data_type once
11294
if @data_type == 'list' || @data_type == 'dummy'
11395
@run_method = method(:list_runner)
@@ -151,30 +133,25 @@ def is_list_type?
151133

152134
# private
153135
def redis_params
136+
params = {
137+
:timeout => @timeout,
138+
:db => @db,
139+
:password => @password.nil? ? nil : @password.value,
140+
:ssl => @ssl
141+
}
142+
154143
if @path.nil?
155-
connectionParams = {
156-
:host => @host,
157-
:port => @port
158-
}
144+
params[:host] = @host
145+
params[:port] = @port
159146
else
160147
@logger.warn("Parameter 'path' is set, ignoring parameters: 'host' and 'port'")
161-
connectionParams = {
162-
:path => @path
163-
}
148+
params[:path] = @path
164149
end
165150

166-
baseParams = {
167-
:timeout => @timeout,
168-
:db => @db,
169-
:password => @password.nil? ? nil : @password.value,
170-
:ssl => @ssl
171-
}
172-
173-
return connectionParams.merge(baseParams)
151+
params
174152
end
175153

176-
# private
177-
def internal_redis_builder
154+
def new_redis_instance
178155
::Redis.new(redis_params)
179156
end
180157

@@ -183,14 +160,12 @@ def connect
183160
redis = new_redis_instance
184161

185162
# register any renamed Redis commands
186-
if @command_map.any?
187-
client_command_map = redis.client.command_map
188-
@command_map.each do |name, renamed|
189-
client_command_map[name.to_sym] = renamed.to_sym
190-
end
163+
@command_map.each do |name, renamed|
164+
redis._client.command_map[name.to_sym] = renamed.to_sym
191165
end
192166

193167
load_batch_script(redis) if batched? && is_list_type?
168+
194169
redis
195170
end # def connect
196171

@@ -221,9 +196,12 @@ def queue_event(msg, output_queue, channel=nil)
221196

222197
# private
223198
def reset_redis
224-
return if @redis.nil? || !@redis.connected?
199+
redis = @redis # might change during method invocation
200+
return if redis.nil? || !redis.connected?
225201

226-
@redis.quit rescue nil
202+
redis.quit rescue nil # does client.disconnect internally
203+
# check if input retried while executing
204+
list_stop unless redis.equal? @redis
227205
@redis = nil
228206
end
229207

@@ -239,13 +217,9 @@ def list_runner(output_queue)
239217
begin
240218
@redis ||= connect
241219
@list_method.call(@redis, output_queue)
242-
rescue ::Redis::BaseError => e
243-
@logger.warn("Redis connection problem", :exception => e)
244-
# Reset the redis variable to trigger reconnect
245-
@redis = nil
246-
# this sleep does not need to be stoppable as its
247-
# in a while !stop? loop
248-
sleep 1
220+
rescue => e
221+
log_error(e)
222+
retry if reset_for_error_retry(e)
249223
end
250224
end
251225
end
@@ -400,18 +374,19 @@ def list_single_listener(redis, output_queue)
400374

401375
# private
402376
def subscribe_stop
403-
return if @redis.nil? || !@redis.connected?
404-
# if its a SubscribedClient then:
405-
# it does not have a disconnect method (yet)
406-
if @redis.client.is_a?(::Redis::SubscribedClient)
377+
redis = @redis # might change during method invocation
378+
return if redis.nil? || !redis.connected?
379+
380+
if redis.subscribed?
407381
if @data_type == 'pattern_channel'
408-
@redis.client.punsubscribe
382+
redis.punsubscribe
409383
else
410-
@redis.client.unsubscribe
384+
redis.unsubscribe
411385
end
412-
else
413-
@redis.client.disconnect
414386
end
387+
redis.close rescue nil # does client.disconnect
388+
# check if input retried while executing
389+
subscribe_stop unless redis.equal? @redis
415390
@redis = nil
416391
end
417392

@@ -420,15 +395,43 @@ def redis_runner
420395
begin
421396
@redis ||= connect
422397
yield
423-
rescue ::Redis::BaseError => e
424-
@logger.warn("Redis connection problem", :exception => e)
425-
# Reset the redis variable to trigger reconnect
426-
@redis = nil
427-
Stud.stoppable_sleep(1) { stop? }
428-
retry if !stop?
398+
rescue => e
399+
log_error(e)
400+
retry if reset_for_error_retry(e)
401+
end
402+
end
403+
404+
def log_error(e)
405+
info = { message: e.message, exception: e.class }
406+
info[:backtrace] = e.backtrace if @logger.debug?
407+
408+
case e
409+
when ::Redis::TimeoutError
410+
# expected for channels in case no data is available
411+
@logger.debug("Redis timeout, retrying", info)
412+
when ::Redis::BaseConnectionError, ::Redis::ProtocolError
413+
@logger.warn("Redis connection error", info)
414+
when ::Redis::BaseError
415+
@logger.error("Redis error", info)
416+
when ::LogStash::ShutdownSignal
417+
@logger.debug("Received shutdown signal")
418+
else
419+
info[:backtrace] ||= e.backtrace
420+
@logger.error("Unexpected error", info)
429421
end
430422
end
431423

424+
# @return [true] if operation is fine to retry
425+
def reset_for_error_retry(e)
426+
return if e.is_a?(::LogStash::ShutdownSignal)
427+
428+
# Reset the redis variable to trigger reconnect
429+
@redis = nil
430+
431+
Stud.stoppable_sleep(1) { stop? }
432+
!stop? # retry if not stop-ing
433+
end
434+
432435
# private
433436
def channel_runner(output_queue)
434437
redis_runner do
@@ -476,6 +479,4 @@ def pattern_channel_listener(output_queue)
476479
end
477480
end
478481

479-
# end
480-
481482
end end end # Redis Inputs LogStash

logstash-input-redis.gemspec

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Gem::Specification.new do |s|
22

33
s.name = 'logstash-input-redis'
4-
s.version = '3.6.0'
4+
s.version = '3.7.0'
55
s.licenses = ['Apache License (2.0)']
66
s.summary = "Reads events from a Redis instance"
77
s.description = "This gem is a Logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This gem is not a stand-alone program"
@@ -23,7 +23,7 @@ Gem::Specification.new do |s|
2323
s.add_runtime_dependency "logstash-core-plugin-api", ">= 1.60", "<= 2.99"
2424

2525
s.add_runtime_dependency 'logstash-codec-json'
26-
s.add_runtime_dependency 'redis', '~> 4'
26+
s.add_runtime_dependency 'redis', '>= 4.0.1', '< 5'
2727

2828
s.add_development_dependency 'logstash-devutils'
2929
end

0 commit comments

Comments
 (0)