Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix compatibility with redis-rb 4.6.0 #192

Merged
merged 1 commit into from
Mar 7, 2022

Conversation

casperisfine
Copy link
Contributor

Fix: #191
Fix: redis/redis-rb#1069
Fix: redis/redis-rb#1088

In redis-rb 4.6.0, the object yielded by multi and pipelined
is an unsynchronized PipelinedConnection object.

This changed opened a thread safety issue in Redis::Namespace:

  • T1: redis.multi do, sets Namespace#redis = PipelinedConnection
  • T2: any command called before T1 exists the multi block is called on the pipelined connection

cc @ArturT, @sergio91pt (extra testing welcome)

@casperisfine casperisfine force-pushed the redis-rb-4.6-compat branch 2 times, most recently from 5dccf88 to b80aefa Compare March 7, 2022 12:28
Fix: resque#191
Fix: redis/redis-rb#1088

In redis-rb 4.6.0, the object yielded by `multi` and `pipelined`
is an unsynchronized `PipelinedConnection` object.

This changed opened a thread safety issue in Redis::Namespace:

  - T1: `redis.multi do`, sets `Namespace#redis = PipelinedConnection`
  - T2: any command called before T1 exists the `multi` block is called on the pipelined connection
@ArturT
Copy link

ArturT commented Mar 7, 2022

Thank you @casperisfine . I've tested your fix locally and it does solve the problem.

# Gemfile
source 'https://rubygems.org'

gem 'redis', path: './redis-rb'
#gem 'redis', '4.5.1'
gem 'redis-namespace', path: './redis-namespace' # local copy of this PR branch
#gem 'redis-namespace'
# reproduce_bug.rb
require 'bundler/setup'
require 'redis'
require 'redis-namespace'

puts "Redis gem version: #{Redis::VERSION}"

key = 'a_key'
threads = []
redis = Redis.new(timeout: 5)
redis = Redis::Namespace.new('my-namespace', redis: redis)

index = 0

while true do
  100.times do
    threads << Thread.new do
      100.times do
        redis.multi do |transaction|
          transaction.incr(key)
          transaction.expire(key, 360)
        end
      end
    end
  end

  threads.each(&:join)

  puts "It works! Iteration: #{index}"
  index += 1
end

Output:

$ ruby reproduce_bug.rb

Redis gem version: 4.6.0
It works! Iteration: 0
It works! Iteration: 1
It works! Iteration: 2
...
It works! Iteration: 1498

@byroot byroot merged commit 0769ffa into resque:master Mar 7, 2022
nevans added a commit to nevans/resque that referenced this pull request Jun 21, 2022
Re-using the connection is no longer supported.  Instead, the block var
must be used.

See also:
* redis/redis-rb#1059
* resque/redis-namespace#192
iloveitaly pushed a commit to resque/resque that referenced this pull request Jun 22, 2022
Re-using the connection is no longer supported.  Instead, the block var
must be used.

See also:
* redis/redis-rb#1059
* resque/redis-namespace#192
jwoodrow pushed a commit to moonproject/resque that referenced this pull request Aug 5, 2022
Re-using the connection is no longer supported.  Instead, the block var
must be used.

See also:
* redis/redis-rb#1059
* resque/redis-namespace#192
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants