diff --git a/lib/redlock/client.rb b/lib/redlock/client.rb index 9a2e839..f538eeb 100644 --- a/lib/redlock/client.rb +++ b/lib/redlock/client.rb @@ -168,13 +168,17 @@ def initialize(connection) def lock(resource, val, ttl, allow_new_lock) recover_from_script_flush do - @redis.call('EVALSHA', Scripts::LOCK_SCRIPT_SHA, 1, resource, val, ttl, allow_new_lock) + @redis.with { |conn| + conn.call('EVALSHA', Scripts::LOCK_SCRIPT_SHA, 1, resource, val, ttl, allow_new_lock) + } end end def unlock(resource, val) recover_from_script_flush do - @redis.call('EVALSHA', Scripts::UNLOCK_SCRIPT_SHA, 1, resource, val) + @redis.with { |conn| + conn.call('EVALSHA', Scripts::UNLOCK_SCRIPT_SHA, 1, resource, val) + } end rescue # Nothing to do, unlocking is just a best-effort attempt. @@ -182,7 +186,9 @@ def unlock(resource, val) def get_remaining_ttl(resource) recover_from_script_flush do - @redis.call('EVALSHA', Scripts::PTTL_SCRIPT_SHA, 1, resource) + @redis.with { |conn| + conn.call('EVALSHA', Scripts::PTTL_SCRIPT_SHA, 1, resource) + } end rescue RedisClient::ConnectionError nil diff --git a/spec/client_spec.rb b/spec/client_spec.rb index 6b99d09..758a5e3 100644 --- a/spec/client_spec.rb +++ b/spec/client_spec.rb @@ -5,7 +5,21 @@ RSpec.describe Redlock::Client do # It is recommended to have at least 3 servers in production let(:lock_manager_opts) { { retry_count: 3 } } - let(:lock_manager) { Redlock::Client.new(Redlock::Client::DEFAULT_REDIS_URLS, lock_manager_opts) } + let(:redis_urls_or_clients) { + urls = Redlock::Client::DEFAULT_REDIS_URLS + if rand(0..1).zero? + RSpec.configuration.reporter.message "variant: client urls" + urls + else + RSpec.configuration.reporter.message "variant: client objects" + urls.map {|url| + ConnectionPool.new { RedisClient.new(url: url) } + } + end + } + let(:lock_manager) { + Redlock::Client.new(redis_urls_or_clients, lock_manager_opts) + } let(:redis_client) { RedisClient.new(url: "redis://#{redis1_host}:#{redis1_port}") } let(:resource_key) { SecureRandom.hex(3) } let(:ttl) { 1000 } @@ -37,9 +51,10 @@ def redis.with it 'accepts ConnectionPool objects' do pool = ConnectionPool.new { RedisClient.new(url: "redis://#{redis1_host}:#{redis1_port}") } - redlock = Redlock::Client.new([pool]) + _redlock = Redlock::Client.new([pool]) lock_info = lock_manager.lock(resource_key, ttl) + expect(lock_info).to be_a(Hash) expect(resource_key).to_not be_lockable(lock_manager, ttl) lock_manager.unlock(lock_info) end @@ -48,7 +63,7 @@ def redis.with redis_client.call('SCRIPT', 'FLUSH') pool = ConnectionPool.new { RedisClient.new(url: "redis://#{redis1_host}:#{redis1_port}") } - redlock = Redlock::Client.new([pool]) + _redlock = Redlock::Client.new([pool]) raw_info = redis_client.call('INFO') number_of_cached_scripts = raw_info[/number_of_cached_scripts\:\d+/].split(':').last @@ -197,7 +212,7 @@ def redis.with 2000 end - lock_manager = Redlock::Client.new(Redlock::Client::DEFAULT_REDIS_URLS, retry_count: 1, retry_delay: retry_delay) + lock_manager = Redlock::Client.new(redis_urls_or_clients, retry_count: 1, retry_delay: retry_delay) another_lock_info = lock_manager.lock(resource_key, ttl) expect(lock_manager).to receive(:sleep) do |sleep| @@ -272,7 +287,9 @@ def redis.with context 'when script cache has been flushed' do before(:each) do @manipulated_instance = lock_manager.instance_variable_get(:@servers).first - @manipulated_instance.instance_variable_get(:@redis).call('SCRIPT', 'FLUSH') + @manipulated_instance.instance_variable_get(:@redis).with { |conn| + conn.call('SCRIPT', 'FLUSH') + } end it 'does not raise a RedisClient::CommandError: NOSCRIPT error' do @@ -475,7 +492,7 @@ def redis.with # Replace redis with unreachable instance redis_instance = lock_manager.instance_variable_get(:@servers).first - old_redis = redis_instance.instance_variable_get(:@redis) + _old_redis = redis_instance.instance_variable_get(:@redis) redis_instance.instance_variable_set(:@redis, unreachable_redis) expect { diff --git a/spec/testing_spec.rb b/spec/testing_spec.rb index 9fc881b..41a4a6f 100644 --- a/spec/testing_spec.rb +++ b/spec/testing_spec.rb @@ -11,7 +11,7 @@ describe '(testing mode)' do describe 'try_lock_instances' do context 'when testing with bypass mode' do - before { lock_manager.testing_mode = :bypass } + before { Redlock::Client.testing_mode = :bypass } it 'bypasses the redis servers' do expect(lock_manager).to_not receive(:try_lock_instances_without_testing) @@ -22,7 +22,7 @@ end context 'when testing with fail mode' do - before { lock_manager.testing_mode = :fail } + before { Redlock::Client.testing_mode = :fail } it 'fails' do expect(lock_manager).to_not receive(:try_lock_instances_without_testing) @@ -33,7 +33,7 @@ end context 'when testing is disabled' do - before { lock_manager.testing_mode = nil } + before { Redlock::Client.testing_mode = nil } it 'works as usual' do expect(lock_manager).to receive(:try_lock_instances_without_testing)