Skip to content

Commit

Permalink
Merge pull request #192 from casperisfine/redis-rb-4.6-compat
Browse files Browse the repository at this point in the history
Fix compatibility with redis-rb 4.6.0
  • Loading branch information
byroot committed Mar 7, 2022
2 parents 7e43f2d + 7f76249 commit 0769ffa
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 19 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
## master

- Fix compatibility with redis-rb 4.6.0. `Redis::Namespace#multi` and `Redis::Namespace#pipelined` were no longer
thread-safe. Calling these methods concurrently onthe same instance could cause pipelines or transaction to be
intertwined. See https://github.com/resque/redis-namespace/issues/191 and https://github.com/redis/redis-rb/issues/1088

## 1.8.1

- Allow Ruby 3.0 version in gemspec
Expand Down
19 changes: 13 additions & 6 deletions lib/redis/namespace.rb
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,12 @@ def call_with_namespace(command, *args, &block)
end
ruby2_keywords(:call_with_namespace) if respond_to?(:ruby2_keywords, true)

protected

def redis=(redis)
@redis = redis
end

private

if Hash.respond_to?(:ruby2_keywords_hash)
Expand Down Expand Up @@ -520,12 +526,13 @@ def call_site
end

def namespaced_block(command, &block)
redis.send(command) do |r|
begin
original, @redis = @redis, r
yield self
ensure
@redis = original
if block.arity == 0
redis.send(command, &block)
else
redis.send(command) do |r|
copy = dup
copy.redis = r
yield copy
end
end
end
Expand Down
36 changes: 23 additions & 13 deletions spec/redis_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,14 @@
@redis_version = Gem::Version.new(Redis.current.info["redis_version"])
let(:redis_client) { @redis.respond_to?(:_client) ? @redis._client : @redis.client}

before(:all) do
before(:each) do
# use database 15 for testing so we dont accidentally step on your real data
@redis = Redis.new :db => 15
end

before(:each) do
@namespaced = Redis::Namespace.new(:ns, :redis => @redis)
@redis.flushdb
@namespaced = Redis::Namespace.new(:ns, :redis => @redis)
@redis.set('foo', 'bar')
end

after(:each) do
@redis.flushdb
end

after(:all) do
@redis.quit
end

# redis-rb 3.3.4+
it "should inject :namespace into connection info" do
info = @redis.connection.merge(:namespace => :ns)
Expand Down Expand Up @@ -398,6 +387,27 @@
expect(result).to eq(["bar", "value"])
end

it "is thread safe for multi blocks" do
mon = Monitor.new
entered = false
entered_cond = mon.new_cond

thread = Thread.new do
mon.synchronize do
entered_cond.wait_until { entered }
@namespaced.multi
end
end

@namespaced.multi do |transaction|
entered = true
mon.synchronize { entered_cond.signal }
thread.join(0.1)
transaction.get("foo")
end
thread.join
end

it "should add namespace to strlen" do
@namespaced.set("mykey", "123456")
expect(@namespaced.strlen("mykey")).to eq(6)
Expand Down

0 comments on commit 0769ffa

Please sign in to comment.