Skip to content

Commit 1e7cbd9

Browse files
committed
pass tries through middleware
1 parent d5f7936 commit 1e7cbd9

File tree

5 files changed

+96
-41
lines changed

5 files changed

+96
-41
lines changed

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -415,15 +415,15 @@ either globally or on a given configuration instance.
415415

416416
```ruby
417417
module MyGlobalRedisInstrumentation
418-
def connect(redis_config)
418+
def connect(redis_config, retry_attempts)
419419
MyMonitoringService.instrument("redis.connect") { super }
420420
end
421421

422-
def call(command, redis_config)
422+
def call(command, redis_config, retry_attempts)
423423
MyMonitoringService.instrument("redis.query") { super }
424424
end
425425

426-
def call_pipelined(commands, redis_config)
426+
def call_pipelined(commands, redis_config, retry_attempts)
427427
MyMonitoringService.instrument("redis.pipeline") { super }
428428
end
429429
end
@@ -443,15 +443,15 @@ If middlewares need a client-specific configuration, `Config#custom` can be used
443443

444444
```ruby
445445
module MyGlobalRedisInstrumentation
446-
def connect(redis_config)
446+
def connect(redis_config, retry_attempts)
447447
MyMonitoringService.instrument("redis.connect", tags: redis_config.custom[:tags]) { super }
448448
end
449449

450-
def call(command, redis_config)
450+
def call(command, redis_config, retry_attempts)
451451
MyMonitoringService.instrument("redis.query", tags: redis_config.custom[:tags]) { super }
452452
end
453453

454-
def call_pipelined(commands, redis_config)
454+
def call_pipelined(commands, redis_config, retry_attempts)
455455
MyMonitoringService.instrument("redis.pipeline", tags: redis_config.custom[:tags]) { super }
456456
end
457457
end

lib/redis_client.rb

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -287,17 +287,17 @@ def pubsub
287287
end
288288

289289
def measure_round_trip_delay
290-
ensure_connected do |connection|
291-
@middlewares.call(["PING"], config) do
290+
ensure_connected do |connection, retry_attempts|
291+
@middlewares.call(["PING"], config, retry_attempts) do
292292
connection.measure_round_trip_delay
293293
end
294294
end
295295
end
296296

297297
def call(*command, **kwargs)
298298
command = @command_builder.generate(command, kwargs)
299-
result = ensure_connected do |connection|
300-
@middlewares.call(command, config) do
299+
result = ensure_connected do |connection, retry_attempts|
300+
@middlewares.call(command, config, retry_attempts) do
301301
connection.call(command, nil)
302302
end
303303
end
@@ -311,8 +311,8 @@ def call(*command, **kwargs)
311311

312312
def call_v(command)
313313
command = @command_builder.generate(command)
314-
result = ensure_connected do |connection|
315-
@middlewares.call(command, config) do
314+
result = ensure_connected do |connection, retry_attempts|
315+
@middlewares.call(command, config, retry_attempts) do
316316
connection.call(command, nil)
317317
end
318318
end
@@ -357,8 +357,8 @@ def call_once_v(command)
357357
def blocking_call(timeout, *command, **kwargs)
358358
command = @command_builder.generate(command, kwargs)
359359
error = nil
360-
result = ensure_connected do |connection|
361-
@middlewares.call(command, config) do
360+
result = ensure_connected do |connection, retry_attempts|
361+
@middlewares.call(command, config, retry_attempts) do
362362
connection.call(command, timeout)
363363
end
364364
rescue ReadTimeoutError => error
@@ -377,8 +377,8 @@ def blocking_call(timeout, *command, **kwargs)
377377
def blocking_call_v(timeout, command)
378378
command = @command_builder.generate(command)
379379
error = nil
380-
result = ensure_connected do |connection|
381-
@middlewares.call(command, config) do
380+
result = ensure_connected do |connection, retry_attempts|
381+
@middlewares.call(command, config, retry_attempts) do
382382
connection.call(command, timeout)
383383
end
384384
rescue ReadTimeoutError => error
@@ -450,9 +450,9 @@ def pipelined(exception: true)
450450
if pipeline._size == 0
451451
[]
452452
else
453-
results = ensure_connected(retryable: pipeline._retryable?) do |connection|
453+
results = ensure_connected(retryable: pipeline._retryable?) do |connection, retry_attempts|
454454
commands = pipeline._commands
455-
@middlewares.call_pipelined(commands, config) do
455+
@middlewares.call_pipelined(commands, config, retry_attempts) do
456456
connection.call_pipelined(commands, pipeline._timeouts, exception: exception)
457457
end
458458
end
@@ -489,9 +489,9 @@ def multi(watch: nil, &block)
489489
if transaction._empty?
490490
[]
491491
else
492-
ensure_connected(retryable: transaction._retryable?) do |connection|
492+
ensure_connected(retryable: transaction._retryable?) do |connection, retry_attempts|
493493
commands = transaction._commands
494-
@middlewares.call_pipelined(commands, config) do
494+
@middlewares.call_pipelined(commands, config, retry_attempts) do
495495
connection.call_pipelined(commands, nil)
496496
end.last
497497
end
@@ -707,7 +707,7 @@ def ensure_connected(retryable: true)
707707

708708
if @disable_reconnection
709709
if block_given?
710-
yield @raw_connection
710+
yield @raw_connection, 0
711711
else
712712
@raw_connection
713713
end
@@ -716,9 +716,9 @@ def ensure_connected(retryable: true)
716716
connection = nil
717717
preferred_error = nil
718718
begin
719-
connection = raw_connection
719+
connection = raw_connection(tries)
720720
if block_given?
721-
yield connection
721+
yield connection, tries
722722
else
723723
connection
724724
end
@@ -744,7 +744,7 @@ def ensure_connected(retryable: true)
744744
connection = ensure_connected
745745
begin
746746
@disable_reconnection = true
747-
yield connection
747+
yield connection, 0
748748
rescue ConnectionError, ProtocolError
749749
close
750750
raise
@@ -754,22 +754,22 @@ def ensure_connected(retryable: true)
754754
end
755755
end
756756

757-
def raw_connection
757+
def raw_connection(retry_attempts = 0)
758758
if @raw_connection.nil? || !@raw_connection.revalidate
759-
connect
759+
connect(retry_attempts)
760760
end
761761
@raw_connection
762762
end
763763

764-
def connect
764+
def connect(retry_attempts = 0)
765765
@pid = PIDCache.pid
766766

767767
if @raw_connection
768-
@middlewares.connect(config) do
768+
@middlewares.connect(config, retry_attempts) do
769769
@raw_connection.reconnect
770770
end
771771
else
772-
@raw_connection = @middlewares.connect(config) do
772+
@raw_connection = @middlewares.connect(config, retry_attempts) do
773773
config.driver.new(
774774
config,
775775
connect_timeout: connect_timeout,
@@ -788,13 +788,13 @@ def connect
788788
# The connection prelude is deliberately not sent to Middlewares
789789
if config.sentinel?
790790
prelude << ["ROLE"]
791-
role, = @middlewares.call_pipelined(prelude, config) do
791+
role, = @middlewares.call_pipelined(prelude, config, retry_attempts) do
792792
@raw_connection.call_pipelined(prelude, nil).last
793793
end
794794
config.check_role!(role)
795795
else
796796
unless prelude.empty?
797-
@middlewares.call_pipelined(prelude, config) do
797+
@middlewares.call_pipelined(prelude, config, retry_attempts) do
798798
@raw_connection.call_pipelined(prelude, nil)
799799
end
800800
end

lib/redis_client/circuit_breaker.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@
33
class RedisClient
44
class CircuitBreaker
55
module Middleware
6-
def connect(config)
6+
def connect(config, _retry_attempts = 0)
77
config.circuit_breaker.protect { super }
88
end
99

10-
def call(_command, config)
10+
def call(_command, config, _retry_attempts = 0)
1111
config.circuit_breaker.protect { super }
1212
end
1313

14-
def call_pipelined(_commands, config)
14+
def call_pipelined(_commands, config, _retry_attempts = 0)
1515
config.circuit_breaker.protect { super }
1616
end
1717
end

lib/redis_client/middlewares.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ def initialize(client)
88
@client = client
99
end
1010

11-
def connect(_config)
11+
def connect(_config, _retry_attempts = 0)
1212
yield
1313
end
1414

15-
def call(command, _config)
15+
def call(command, _config, _retry_attempts = 0)
1616
yield command
1717
end
1818
alias_method :call_pipelined, :call

test/redis_client/middlewares_test.rb

Lines changed: 60 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ def setup
1414
RedisClient.register(TestMiddleware)
1515
super
1616
TestMiddleware.calls.clear
17+
InstrumentRetryAttemptsMiddleware.calls.clear
1718
end
1819

1920
def teardown
@@ -22,6 +23,7 @@ def teardown
2223
RedisClient.const_set(:Middlewares, @original_module)
2324
end
2425
TestMiddleware.calls.clear
26+
InstrumentRetryAttemptsMiddleware.calls.clear
2527
super
2628
end
2729

@@ -70,11 +72,11 @@ def test_multi_instrumentation
7072
end
7173

7274
module DummyMiddleware
73-
def call(command, _config, &_)
75+
def call(command, _config, _retry_attempts = 0, &_)
7476
command
7577
end
7678

77-
def call_pipelined(commands, _config, &_)
79+
def call_pipelined(commands, _config, _retry_attempts = 0, &_)
7880
commands
7981
end
8082
end
@@ -85,6 +87,25 @@ def test_instance_middleware
8587
assert_equal([["GET", "2"]], second_client.pipelined { |p| p.call("GET", 2) })
8688
end
8789

90+
def test_retry_instruments_attempts
91+
client = new_client(reconnect_attempts: 1, middlewares: [InstrumentRetryAttemptsMiddleware])
92+
93+
simulate_network_errors(client, ["PING"]) do
94+
client.call("PING")
95+
end
96+
97+
assert_includes InstrumentRetryAttemptsMiddleware.calls, [:call, :error, ["PING"], 0]
98+
assert_includes InstrumentRetryAttemptsMiddleware.calls, [:call, :success, ["PING"], 1]
99+
end
100+
101+
def test_connect_instruments_attempts
102+
client = new_client(middlewares: [InstrumentRetryAttemptsMiddleware])
103+
104+
client.call("PING")
105+
106+
assert_includes InstrumentRetryAttemptsMiddleware.calls, [:connect, :success, 0]
107+
end
108+
88109
private
89110

90111
def assert_call(call)
@@ -102,7 +123,7 @@ class << self
102123
end
103124
@calls = []
104125

105-
def connect(config)
126+
def connect(config, _retry_attempts = 0)
106127
result = super
107128
TestMiddleware.calls << [:connect, :success, result, config]
108129
result
@@ -111,7 +132,7 @@ def connect(config)
111132
raise
112133
end
113134

114-
def call(command, config)
135+
def call(command, config, _retry_attempts = 0)
115136
result = super
116137
TestMiddleware.calls << [:call, :success, command, result, config]
117138
result
@@ -120,7 +141,7 @@ def call(command, config)
120141
raise
121142
end
122143

123-
def call_pipelined(commands, config)
144+
def call_pipelined(commands, config, _retry_attempts = 0)
124145
result = super
125146
TestMiddleware.calls << [:pipeline, :success, commands, result, config]
126147
result
@@ -129,5 +150,39 @@ def call_pipelined(commands, config)
129150
raise
130151
end
131152
end
153+
154+
module InstrumentRetryAttemptsMiddleware
155+
class << self
156+
attr_accessor :calls
157+
end
158+
@calls = []
159+
160+
def connect(config, retry_attempts = 0)
161+
result = super
162+
InstrumentRetryAttemptsMiddleware.calls << [:connect, :success, retry_attempts]
163+
result
164+
rescue
165+
InstrumentRetryAttemptsMiddleware.calls << [:connect, :error, retry_attempts]
166+
raise
167+
end
168+
169+
def call(command, config, retry_attempts = 0)
170+
result = super
171+
InstrumentRetryAttemptsMiddleware.calls << [:call, :success, command, retry_attempts]
172+
result
173+
rescue
174+
InstrumentRetryAttemptsMiddleware.calls << [:call, :error, command, retry_attempts]
175+
raise
176+
end
177+
178+
def call_pipelined(commands, config, retry_attempts = 0)
179+
result = super
180+
InstrumentRetryAttemptsMiddleware.calls << [:pipeline, :success, commands, retry_attempts]
181+
result
182+
rescue
183+
InstrumentRetryAttemptsMiddleware.calls << [:pipeline, :error, commands, retry_attempts]
184+
raise
185+
end
186+
end
132187
end
133188
end

0 commit comments

Comments
 (0)