Skip to content

Instantly share code, notes, and snippets.

@stevehodgkiss
Last active August 29, 2015 13:58
Show Gist options
  • Save stevehodgkiss/10204388 to your computer and use it in GitHub Desktop.
Save stevehodgkiss/10204388 to your computer and use it in GitHub Desktop.
Redis issues with Timeout on Ruby 2.1.1
require 'redis'
require 'securerandom'
require 'timeout'
describe 'timeout/redis issues' do
def reconnect
$redis = Redis.new(db: 1, :port => ENV.fetch('BOXEN_REDIS_PORT', '6379'))
end
def ruby_211_timeout(sec, klass = nil)
return yield(sec) if sec == nil or sec.zero?
message = "execution expired"
e = Timeout::Error
bl = proc do |exception|
begin
x = Thread.current
y = Thread.start {
begin
sleep sec
rescue => e
x.raise e
else
x.raise exception, message
end
}
return yield(sec)
ensure
if y
y.kill
y.join # make sure y is dead.
end
end
end
if klass
begin
bl.call(klass)
rescue klass => e
bt = e.backtrace
end
else
bt = Timeout::ExitException.catch(message, &bl)
end
rej = /\A#{Regexp.quote(__FILE__)}:#{__LINE__-4}\z/o
bt.reject! {|m| rej =~ m}
level = -caller(Timeout::CALLER_OFFSET).size
while Timeout::THIS_FILE =~ bt[level]
bt.delete_at(level)
end
raise(e, message, bt)
end
def ruby_19_timeout(sec, klass = nil)
return yield(sec) if sec == nil or sec.zero?
exception = klass || Class.new(Timeout::ExitException)
begin
begin
x = Thread.current
y = Thread.start {
begin
sleep sec
rescue => e
x.raise e
else
x.raise exception, "execution expired"
end
}
return yield(sec)
ensure
if y
y.kill
y.join # make sure y is dead.
end
end
rescue exception => e
rej = /\A#{Regexp.quote(__FILE__)}:#{__LINE__-4}\z/o
(bt = e.backtrace).reject! {|m| rej =~ m}
level = -caller(Timeout::CALLER_OFFSET).size
while Timeout::THIS_FILE =~ bt[level]
bt.delete_at(level)
level += 1
end
raise if klass # if exception class is specified, it
# would be expected outside.
raise Timeout::Error, e.message, e.backtrace
end
end
def timeout_193
ruby_19_timeout(0.1) do
loop { $redis.keys('*') }
end
rescue Timeout::Error
end
def timeout_211
ruby_211_timeout(0.1) do
loop { $redis.keys('*') }
end
rescue Timeout::Error
end
before do
reconnect
$redis.flushdb
$redis.set(key, value)
1000.times do
$redis.set('some other key', 'testing')
end
end
let(:key) { 'key_1' }
let(:value) { 'value_1' }
it "returns the correct value on 1.9.3's timeout implementation" do
timeout_193
expect($redis.get(key)).to eq value
end
it "returns the correct value on 2.1.1's timeout implementation" do
timeout_211
expect($redis.get(key)).to eq value
end
end
@stevehodgkiss
Copy link
Author

~/src/10204388 master
❯ rspec redis_timeout_issue_spec.rb
.F

Failures:

  1) timeout/redis issues a timeout error occurs with ruby 2.1.1's timeout implementation behaves like returns correct values returns the correct info for 6 alternating gets
     Failure/Error: expect($redis.get(key)).to eq value

       expected: "value_1"
            got: ["some other key", "key_1"]

       (compared using ==)
     Shared Example Group: "returns correct values" called from ./redis_timeout_issue_spec.rb:134
     # ./redis_timeout_issue_spec.rb:117:in `block (3 levels) in <top (required)>'

Finished in 0.34552 seconds (files took 0.14777 seconds to load)
2 examples, 1 failure

Failed examples:

rspec ./redis_timeout_issue_spec.rb:116 # timeout/redis issues a timeout error occurs with ruby 2.1.1's timeout implementation behaves like returns correct values returns the correct info for 6 alternating gets

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment