diff --git a/lib/redis/semaphore.rb b/lib/redis/semaphore.rb index 22e1645..590da03 100644 --- a/lib/redis/semaphore.rb +++ b/lib/redis/semaphore.rb @@ -19,13 +19,17 @@ def initialize(name, opts = {}) @expiration = opts.delete(:expiration) @resource_count = opts.delete(:resources) || 1 @stale_client_timeout = opts.delete(:stale_client_timeout) - @redis = opts.delete(:redis) || Redis.new(opts) @use_local_time = opts.delete(:use_local_time) + @redis = if @redis = opts.delete(:redis) + @redis.dup + else + Redis.new(opts) + end @tokens = [] end def exists_or_create! - token = @redis.getset(exists_key, EXISTS_TOKEN) + token = @redis.get(exists_key) if token.nil? create! @@ -90,11 +94,7 @@ def locked?(token = nil) if token @redis.hexists(grabbed_key, token) else - @tokens.each do |token| - return true if locked?(token) - end - - false + @tokens.any? { |t| locked?(t) } end end @@ -156,7 +156,7 @@ def simple_mutex(key_name, expires = nil) end def create! - @redis.expire(exists_key, 10) + @redis.setex(exists_key, 10, EXISTS_TOKEN) @redis.multi do @redis.del(grabbed_key) diff --git a/spec/semaphore_spec.rb b/spec/semaphore_spec.rb index 75fdbd3..3da7b23 100644 --- a/spec/semaphore_spec.rb +++ b/spec/semaphore_spec.rb @@ -125,6 +125,23 @@ expect(@redis.keys.count).to eq(original_key_size) end + + it "don't enters deadlock" do + i = 0 + expect { + redis = @redis.dup + Timeout.timeout(2) do + Array.new(2).map do + Thread.new do + Redis::Semaphore.new(:sem, redis: redis).lock do + i += 1 + end + end + end.each(&:join) + end + }.not_to raise_error + expect(i).to eq(2) + end end describe "semaphore with expiration" do @@ -211,7 +228,8 @@ end it "without time support should return the same time as frozen time" do - expect(@redis).to receive(:time).and_raise(Redis::CommandError) + expect(semaphore.instance_variable_get(:@redis)).to receive(:time) + .and_raise(Redis::CommandError) expect(semaphore.send(:current_time)).to eq(Time.now) end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 1eff8be..05a660a 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -4,4 +4,5 @@ $TESTING=true $:.unshift File.join(File.dirname(__FILE__), '..', 'lib') +require 'timeout' require 'redis/semaphore'