Im trying to test memory allocation. And choose for it rspec-benchmark gem. But found some strange behaviour I don't understand. To reproduce it we can write spec like this:
require 'rails_helper'
describe ApplicationsManagement::Export do
let(:applications_collection) { create_list(:application, 1 ) }
describe '#call' do
it 'comsumpts not more 1 MB' do
i = 0
expect { applications_collection.each { |app| puts i += 1 } }.to perform_allocation(1_048_576).bytes
end
end
end
When we run spec we have to wait few minutes!!
ApplicationsManagement::Export
#call
1
comsumpts not more 1 MB (FAILED - 1)
Failures:
1) ApplicationsManagement::Export#call comsumpts not more 1 MB
Failure/Error: expect { applications_collection.each { |app| puts i += 1 } }.to perform_allocation(1_048_576).bytes
expected block to perform allocation of 1048576 bytes, but allocated 10694166 bytes
# ./spec/services/applications_management/export_spec.rb:16:in `block (3 levels) in <top (required)>'
# ./spec/rails_helper.rb:55:in `block (3 levels) in <top (required)>'
# ./spec/rails_helper.rb:54:in `block (2 levels) in <top (required)>'
Finished in 4 minutes 8.5 seconds (files took 21.99 seconds to load)
1 example, 1 failure
To be honest, it was the first time I see the output, because I didn't wait never. Anyway its too long time for only one application creating and allocating 1 Mb memory. What am I doing wrong, why this spec is running so long?
spec/rails_helper.rb
require 'rspec-benchmark'
RSpec.configure do |config|
config.include RSpec::Benchmark::Matchers
...
P.S:
rails 4.2.9
rspec (3.5.0)
rspec-core (~> 3.5.0)
rspec-expectations (~> 3.5.0)
rspec-mocks (~> 3.5.0)
rspec-benchmark (0.5.1)
benchmark-malloc (~> 0.1.0)
benchmark-perf (~> 0.5.0)
benchmark-trend (~> 0.3.0)
rspec (>= 3.0.0, < 4.0.0)
rspec-core (3.5.4)
rspec-support (~> 3.5.0)
Thank you so much!
I've found that if I pass FactoryBot.create(...) to the expect block, then I got the stuck behaviour. But if one row before I have initialized the objects. Then example working as expected.
require 'rails_helper'
describe ApplicationsManagement::Export do
let(:applications_collection) { create_list(:application, 1) }
describe '#call' do
it 'comsumpts not more 1 MB' do
applications_collection
i = 0
expect { applications_collection.each { |app| puts i += 1 } }.to perform_allocation(1_048_576).bytes
end
end
end
ApplicationsManagement::Export
#call
1
comsumpts not more 1 MB
Finished in 1.17 seconds (files took 21.71 seconds to load)
1 example, 0 failures
Related
I have a page with a link that opens a bootstrap modal with a simple input field. I'm having a hard time understanding why Capybara doesn't wait for the modal to open, and fails immediately.
I added expect(page).to have_content('Did you') so capybara will wait a few seconds until the modal is shown.
But for some reason it's not waiting and raises Capybara::ExpectationNotMet: expected to find text "Did you" in ...."
If I put a sleep of 1 second it will then find the modal, but it's not good enough because then a DB clean callback found in my spec_helper.rb is called:
config.after(:each) do
DatabaseCleaner.clean
end
This is the spec:
RSpec.describe "follower button", type: :request do
it "sends email #15B to owner", :js do
using_wait_time 20 do
FactoryGirl.create(:apartment_with_event)
visit apartment_path(Apartment.last)
click_on 'follow-events'
expect(page).to have_content('Did you')
within('#follow-events-modal') do
fill_in 'follower-email-signup-mail', with: 'follower#example.com'
click_button 'follower-signup-submit'
end
expect(page).to have_content(I18n.t("followers.create.title_success"))
expect(Follower.all.count).to eq(1)
end
end
end
I also set Capybara.default_max_wait_time = 10 in spec_helper.rb, even though it should wait for 20 seconds for this example.
Forgot to mention, I'm using Capybara-wekbit as the driver.
I really spent hours trying to discover why it's happening, while other examples run just fine.
UPDATE:
Adding full backtrace of failure.
Failures:
1) leeron's button sends email #15B to owner
Failure/Error: raise ActionController::RoutingError, "No route matches [#{env['REQUEST_METHOD']}] #{env['PATH_INFO'].inspect}"
ActionController::RoutingError:
No route matches [GET] "/images/slider/missing.png"
# /Users/etaiso/.rbenv/versions/2.2.3/gemsets/dorbel/gems/rollbar-1.2.13/lib/rollbar/middleware/rails/show_exceptions.rb:22:in `call_with_rollbar'
# /Users/etaiso/.rbenv/versions/2.2.3/gemsets/dorbel/gems/railties-4.2.4/lib/rails/rack/logger.rb:38:in `call_app'
# /Users/etaiso/.rbenv/versions/2.2.3/gemsets/dorbel/gems/railties-4.2.4/lib/rails/rack/logger.rb:20:in `block in call'
# /Users/etaiso/.rbenv/versions/2.2.3/gemsets/dorbel/gems/railties-4.2.4/lib/rails/rack/logger.rb:20:in `call'
# /Users/etaiso/.rbenv/versions/2.2.3/gemsets/dorbel/gems/request_store-1.2.0/lib/request_store/middleware.rb:8:in `call'
# /Users/etaiso/.rbenv/versions/2.2.3/gemsets/dorbel/gems/rack-1.6.4/lib/rack/methodoverride.rb:22:in `call'
# /Users/etaiso/.rbenv/versions/2.2.3/gemsets/dorbel/gems/rack-1.6.4/lib/rack/runtime.rb:18:in `call'
# /Users/etaiso/.rbenv/versions/2.2.3/gemsets/dorbel/gems/rack-1.6.4/lib/rack/lock.rb:17:in `call'
# /Users/etaiso/.rbenv/versions/2.2.3/gemsets/dorbel/gems/rack-1.6.4/lib/rack/sendfile.rb:113:in `call'
# /Users/etaiso/.rbenv/versions/2.2.3/gemsets/dorbel/gems/railties-4.2.4/lib/rails/engine.rb:518:in `call'
# /Users/etaiso/.rbenv/versions/2.2.3/gemsets/dorbel/gems/railties-4.2.4/lib/rails/application.rb:165:in `call'
# /Users/etaiso/.rbenv/versions/2.2.3/gemsets/dorbel/gems/rack-1.6.4/lib/rack/urlmap.rb:66:in `block in call'
# /Users/etaiso/.rbenv/versions/2.2.3/gemsets/dorbel/gems/rack-1.6.4/lib/rack/urlmap.rb:50:in `each'
# /Users/etaiso/.rbenv/versions/2.2.3/gemsets/dorbel/gems/rack-1.6.4/lib/rack/urlmap.rb:50:in `call'
# /Users/etaiso/.rbenv/versions/2.2.3/gemsets/dorbel/gems/capybara-2.7.1/lib/capybara/server.rb:43:in `call'
# /Users/etaiso/.rbenv/versions/2.2.3/gemsets/dorbel/gems/rack-1.6.4/lib/rack/handler/webrick.rb:88:in `service'
# ------------------
# --- Caused by: ---
# Capybara::ExpectationNotMet:
# expected to find text "Did you" in "...(REMOVED BY ME TO SAVE SPACE)..."
# /Users/etaiso/.rbenv/versions/2.2.3/gemsets/dorbel/gems/capybara-2.7.1/lib/capybara/node/matchers.rb:527:in `block in assert_text'
Finished in 3.87 seconds (files took 9.79 seconds to load)
1 example, 1 failure
From the callback we can see that the actual exception is a routing error from the app. While Capybara is retrying/waiting on finders and expectations it checks for server thrown errors and if Capybara.raise_server_errors is true it will raise them in the test thread so they are visible to tests. A side-effect of the re-raising of exceptions from the app thread in the test thread is that any current exception in the test thread (such as ExpectationNotMet) which would normally be handled and retried by Capybara gets set by ruby as the nested cause of the apps exception. It isn't really the cause but we can't because of the way Capybara re-raises the server error it shows up there. You can either set Capybara.raise_server_errors = false or better yet, fix the missing image.
I am using the APIonRails tutorial and they have this:
require 'spec_helper'
describe ApiConstraints do
let(:api_constraints_v1) { ApiConstraints.new(version: 1) }
let(:api_constraints_v2) { ApiConstraints.new(version: 2, default: true) }
describe "matches?" do
it "returns true when the version matches the 'Accept' header" do
request = double(host: 'api.marketplace.dev',
headers: {"Accept" => "application/vnd.marketplace.v1"})
api_constraints_v1.matches?(request).should be_true
end
it "returns the default version when 'default' option is specified" do
request = double(host: 'api.marketplace.dev')
api_constraints_v2.matches?(request).should be_true
end
end
end
In an example, but I have come to understand that this is using the old syntax.
To convert this into the new syntax, I am trying this:
require 'rails_helper'
describe ApiConstraints do
let(:api_constraints_v1) { ApiConstraints.new(version: 1) }
let(:api_constraints_v2) { ApiConstraints.new(version: 2, default: true) }
describe "matches?" do
it "returns true when the version matches the 'Accept' header" do
request = double(host: 'api.localhost:3000',
headers: {"Accept" => "application/vnd.marketplace.v1"})
expect(request).to match(api_constraints_v1)
end
it "returns the default version when 'default' option is specified" do
request = double(host: 'api.localhost:3000')
expect api_constraints_v2.matches?(request).to_be true
end
end
end
This is the error I am getting:
Failures:
1) ApiConstraints matches? returns true when the version matches the 'Accept' header
Failure/Error: expect(request).to match(api_constraints_v1)
expected #<RSpec::Mocks::Double:0x3feeedaf60c4 #name=nil> to match #<ApiConstraints:0x007fddde50f9b0 #version=1, #default=nil>
Diff:
## -1,2 +1,2 ##
-#<ApiConstraints:0x007fddde50f9b0 #default=nil, #version=1>
+#<RSpec::Mocks::Double:0x3feeedaf60c4 #name=nil>
# ./lib/spec/api_constraints_spec.rb:11:in `block (3 levels) in <top (required)>'
2) ApiConstraints matches? returns the default version when 'default' option is specified
Failure/Error: expect api_constraints_v2.matches?(request).to_be true
NoMethodError:
undefined method `to_be' for true:TrueClass
Did you mean? to_enum
to_s
# ./lib/spec/api_constraints_spec.rb:16:in `block (3 levels) in <top (required)>'
Finished in 0.0045 seconds (files took 6.52 seconds to load)
2 examples, 2 failures
Failed examples:
rspec ./lib/spec/api_constraints_spec.rb:8 # ApiConstraints matches? returns true when the version matches the 'Accept' header
rspec ./lib/spec/api_constraints_spec.rb:14 # ApiConstraints matches? returns the default version when 'default' option is specified
What could be causing this?
Edit 1
Per My Gemfile.lock, these are the versions of my relevant gems:
rspec (3.1.0)
rspec-core (~> 3.1.0)
rspec-expectations (~> 3.1.0)
rspec-mocks (~> 3.1.0)
rspec-core (3.1.7)
rspec-support (~> 3.1.0)
rspec-expectations (3.1.2)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.1.0)
rspec-mocks (3.1.3)
rspec-support (~> 3.1.0)
rspec-rails (3.1.0)
actionpack (>= 3.0)
activesupport (>= 3.0)
railties (>= 3.0)
rspec-core (~> 3.1.0)
rspec-expectations (~> 3.1.0)
rspec-mocks (~> 3.1.0)
rspec-support (~> 3.1.0)
rspec-support (3.1.2)
rubyzip (1.2.0)
selenium-webdriver (2.53.0)
childprocess (~> 0.5)
rubyzip (~> 1.0)
websocket (~> 1.0)
shellany (0.0.1)
shoulda (3.5.0)
shoulda-context (~> 1.0, >= 1.0.1)
shoulda-matchers (>= 1.4.1, < 3.0)
shoulda-context (1.2.1)
shoulda-matchers (2.8.0)
activesupport (>= 3.0.0)
What is the correct new syntax I should use to be able to achieve the same thing that the original code achieves?
In the original test change
api_constraints_v1.matches?(request).should be_true
to
expect(api_constraints_v1.matches?(request)).to be_truthy
or
expect(api_constraints_v1.matches?(request)).to be(true)
if you expect only a boolean value to be returned.
change
expect request.to eq(api_constraints_v1)
to
expect(request).to eq(api_constraints_v1)
and the same problem in the other spec...
expect is a method to which you give the thing that the expectation is going on (ie request)...
after you get the result from the request method - you then call to on it...
The way you had it before... you are first calling to on request and then passing the result of that to expect... ie, grouping matters ;)
I've used the same ApiConstraints in my rails-api-base project and it crashes when you try matches? with a non-default version without specifying the Accept header.
I added the following test (which crashes):
it 'returns false when not default and no Accept header' do
request = double(host: 'api.marketplace.dev')
expect(api_constraints_v1.matches?(request)).to be false
end
And I fixed ApiConstraints:
def matches?(req)
#default ||
(req.respond_to?('headers') &&
req.headers.key?('Accept') &&
req.headers['Accept'].include?("application/vnd.marketplace.v#{#version}"))
end
Hope it helps!
I'd like to add a vendor? function to Spree::User.
So I created app/models/spree/user.rb
module Spree
class User < Spree::Base
include Spree::UserMethods
def vendor?
self.role_users.any? { |ru| ru.role.name == 'vendor' }
end
end
end
This works if I start rails console and test:
u = Spree::User.last; u.vendor? # => false
But when I start rails server and visit a page I get this error:
NoMethodError in Spree::Admin::OrdersController#index
undefined method `serialize_from_session' for #
Stack trace
activerecord (4.2.5) lib/active_record/dynamic_matchers.rb:26:in `method_missing'
devise (3.5.4) lib/devise.rb:465:in `block (2 levels) in configure_warden!'
warden (1.2.4) lib/warden/session_serializer.rb:34:in `fetch'
warden (1.2.4) lib/warden/proxy.rb:212:in `user'
warden (1.2.4) lib/warden/proxy.rb:322:in `_perform_authentication'
warden (1.2.4) lib/warden/proxy.rb:104:in `authenticate'
devise (3.5.4) lib/devise/controllers/helpers.rb:124:in `current_spree_user'
solidus_auth_devise (1.3.0) lib/spree/authentication_helpers.rb:11:in `spree_current_user'
solidus/core/lib/spree/core/controller_helpers/auth.rb:67:in `try_spree_current_user'
solidus/core/lib/spree/core/controller_helpers/auth.rb:31:in `current_ability'
cancancan (1.13.1) lib/cancan/controller_additions.rb:338:in `authorize!'
solidus/backend/app/controllers/spree/admin/base_controller.rb:22:in `authorize_admin'
Any idea what I should do to fix this error? According to the stack trace it looks like I'm missing a method somewhere.
Cheers,
Martin
The answer is to open the Spree::User class and add the methods you're missing:
E.g:
config/initializers/spree_user.rb
Spree::User.class_eval do
def vendor?
self.role_users.any? { |ru| ru.role.name == 'vendor' }
end
end
The expect(page).to have_content syntax is legal according to the capybara docs, but it does not seem to work
I have added the spec file and the error below
require 'spec_helper.rb'
feature "Looking up recipes", js: true do
before do
Recipe.create!(name: 'Baked Potato w/ Cheese')
Recipe.create!(name: 'Garlic Mashed Potatoes')
Recipe.create!(name: 'Potatoes Au Gratin')
Recipe.create!(name: 'Baked Brussel Sprouts')
end
scenario "finding recipes" do
visit '/'
fill_in "keywords", with: "baked"
click_on "Search"
expect(page).to have_content("Baked Potato")
expect(page).to have_content("Baked Brussel Sprouts")
end
end
Error when running spec:
sai#saip:~/rails_apps/receta$ rspec spec/features/search_spec.rb
F
Failures:
1) Looking up recipes finding recipes
Failure/Error: expect(page).to have_content("Baked Potato")
only the `receive` matcher is supported with `expect(...).to`, but you have provided: #<Capybara::RSpecMatchers::HaveText:0x000000057c0470>
# ./spec/features/search_spec.rb:15:in `block (2 levels) in <top (required)>'
Finished in 9.95 seconds
1 example, 1 failure
Failed examples:
rspec ./spec/features/search_spec.rb:10 # Looking up recipes finding recipes
Randomized with seed 31312
These are the versions of the various rspec gems
rspec (2.99.0)
rspec-collection_matchers (1.1.2)
rspec-core (2.99.2)
rspec-expectations (2.99.2)
rspec-mocks (2.99.3)
rspec-rails (2.99.0)
The vesion of capybara is capybara (2.4.4)
You're using the wrong version of RSpec for that syntax. The use of expect(...).to ... is the accepted way of writing tests in RSpec 3+. You're using 2.99.
Your syntax is
page.should have_content("Baked Potato")
You should really upgrade RSpec.
Updated to include Redis/Resque versions and stack trace (below):
redis (3.0.4)
redis-namespace (1.3.0)
redis (~> 3.0.0)
redis-store (1.1.2)
redis (>= 2.2.0)
resque (1.24.1)
mono_logger (~> 1.0)
multi_json (~> 1.0)
redis-namespace (~> 1.2)
sinatra (>= 0.9.2)
vegas (~> 0.1.2)
resque-scheduler (2.0.1)
redis (>= 2.0.1)
resque (>= 1.20.0)
rufus-scheduler
I'm seeing intermittent Redis::TimeoutError: Connection timed out on heroku while writing a moderately sized array (~200 Fixnums) to the Redis store using the Rails.cache.fetch command.
I'm also using Resque.
I see here that the Redis::Client can receive a timeout option, but I don't see where to pass initialization options to Redis.
I'm using the standard heroku resque.rb:
rails_root = ENV['RAILS_ROOT'] || File.dirname(__FILE__) + '/../..'
rails_env = ENV['RAILS_ENV'] || 'development'
resque_config = YAML.load_file(rails_root + '/config/resque.yml')
ENV['REDIS_URI'] = resque_config[rails_env]
Resque.redis = resque_config[rails_env]
Resque.inline = rails_env == 'test'
require 'resque_scheduler'
require 'resque/scheduler'
require 'resque_scheduler/server'
Resque.schedule = YAML.load_file(rails_root + '/config/resque-schedule.yml')
Resque.before_fork do
defined?(ActiveRecord::Base) and
ActiveRecord::Base.connection.disconnect!
end
Resque.after_fork do
defined?(ActiveRecord::Base) and
ActiveRecord::Base.establish_connection
end
I assume that a Redis client is instantiated here. Is this a different client from the one instantiated in production.rb:
rails_root = ENV['RAILS_ROOT'] || File.dirname(__FILE__) + '/../..'
rails_env = ENV['RAILS_ENV'] || 'development'
resque_config = YAML.load_file(rails_root + '/config/resque.yml')
config.cache_store = :redis_store, resque_config[rails_env], { expires_in: 14.days }
The options hash there is for Rails.cache options as far as I know. Is a new client instantiated here? How can I pass options to this one?
Updated to include this experiment in the heroku console implying that they are different client instances:
irb(main):002:0> Rails.cache
=> #<ActiveSupport::Cache::RedisStore:0x00000003860e18 #data=#<Redis client v3.0.4 for redis://spinyfin.redistogo.com:9485/0>, #options={:expires_in=>14 days}>
irb(main):003:0> Resque.redis.redis
=> #<Redis client v3.0.4 for redis://spinyfin.redistogo.com:9485/0>
irb(main):004:0> Rails.cache.instance_variable_get(:#data).object_id == Resque.redis.redis.object_id
=> false
Stack trace:
Redis::TimeoutError: Connection timed out
from /app/vendor/bundle/ruby/1.9.1/gems/redis-3.0.4/lib/redis/client.rb:208:in `rescue in io'
from /app/vendor/bundle/ruby/1.9.1/gems/redis-3.0.4/lib/redis/client.rb:206:in `io'
from /app/vendor/bundle/ruby/1.9.1/gems/redis-3.0.4/lib/redis/client.rb:214:in `read'
from /app/vendor/bundle/ruby/1.9.1/gems/redis-3.0.4/lib/redis/client.rb:84:in `block in call'
from /app/vendor/bundle/ruby/1.9.1/gems/redis-3.0.4/lib/redis/client.rb:187:in `block (2 levels) in process'
from /app/vendor/bundle/ruby/1.9.1/gems/redis-3.0.4/lib/redis/client.rb:295:in `ensure_connected'
from /app/vendor/bundle/ruby/1.9.1/gems/redis-3.0.4/lib/redis/client.rb:177:in `block in process'
from /app/vendor/bundle/ruby/1.9.1/gems/redis-3.0.4/lib/redis/client.rb:256:in `logging'
from /app/vendor/bundle/ruby/1.9.1/gems/redis-3.0.4/lib/redis/client.rb:176:in `process'
from /app/vendor/bundle/ruby/1.9.1/gems/redis-3.0.4/lib/redis/client.rb:84:in `call'
from /app/vendor/bundle/ruby/1.9.1/gems/redis-3.0.4/lib/redis.rb:644:in `block in setex'
from /app/vendor/bundle/ruby/1.9.1/gems/redis-3.0.4/lib/redis.rb:36:in `block in synchronize'
from /app/vendor/ruby-1.9.3/lib/ruby/1.9.1/monitor.rb:211:in `mon_synchronize'
from /app/vendor/bundle/ruby/1.9.1/gems/redis-3.0.4/lib/redis.rb:36:in `synchronize'
from /app/vendor/bundle/ruby/1.9.1/gems/redis-3.0.4/lib/redis.rb:643:in `setex'
from /app/vendor/bundle/ruby/1.9.1/gems/redis-store-1.1.2/lib/redis/store/interface.rb:17:in `setex'
... 11 levels...
from /app/vendor/bundle/ruby/1.9.1/gems/activesupport-3.2.13/lib/active_support/cache.rb:299:in `fetch'
...SNIP...
...my code...
...SNIP...
from /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.13/lib/active_record/relation/delegation.rb:6:in `each'
from /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.13/lib/active_record/relation/delegation.rb:6:in `each'
...SNIP...
...my code...
...SNIP...
from (irb):5
from /app/vendor/bundle/ruby/1.9.1/gems/railties-3.2.13/lib/rails/commands/console.rb:47:in `start'
from /app/vendor/bundle/ruby/1.9.1/gems/railties-3.2.13/lib/rails/commands/console.rb:8:in `start'
from /app/vendor/bundle/ruby/1.9.1/gems/railties-3.2.13/lib/rails/commands.rb:41:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'irb(main):006:0> ! Heroku client internal error.
! Search for help at: https://help.heroku.com
! Or report a bug at: https://github.com/heroku/heroku/issues/new
Error: Operation timed out (Errno::ETIMEDOUT)
Backtrace: /usr/local/heroku/ruby/lib/ruby/1.9.1/openssl/buffering.rb:121:in `sysread'
/usr/local/heroku/ruby/lib/ruby/1.9.1/openssl/buffering.rb:121:in `readpartial'
/Users/me/.heroku/client/lib/heroku/client/rendezvous.rb:69:in `block in start'
/Users/me/.heroku/client/lib/heroku/client/rendezvous.rb:53:in `loop'
/Users/me/.heroku/client/lib/heroku/client/rendezvous.rb:53:in `start'
/Users/me/.heroku/client/lib/heroku/command/run.rb:132:in `rendezvous_session'
/Users/me/.heroku/client/lib/heroku/command/run.rb:119:in `run_attached'
/Users/me/.heroku/client/lib/heroku/command/run.rb:24:in `index'
/Users/me/.heroku/client/lib/heroku/command.rb:206:in `run'
/Users/me/.heroku/client/lib/heroku/cli.rb:28:in `start'
/usr/local/heroku/bin/heroku:24:in `<main>'
Command: heroku run rails c
Plugins: heroku-redis-cli
Version: heroku-toolbelt/2.39.4 (x86_64-darwin10.8.0) ruby/1.9.3
The "Connection timed out" message means that redis-rb is having trouble initiating a connection to your Redis server. Normally, you'd want to just initialize your Redis connection once on app boot. However, because Resque forks (rather than using threads like Sidekiq), it has to initialize a fresh Redis connection for every individual job.
Normally, that's not a problem, but Heroku has intermittent issues with creating new Redis connections. I've seen this issue across languages / client libraries / Redis hosts, and beyond reducing the number of Redis connections you create, the only way to mitigate the issue is to automatically retry connecting to Redis a few times in your Resque.after_fork block. (Eg. catch the timeout error and either retry or re-raise the exception if you've tried 3 times)
This isn't much of an answer, but at the recommendation of a colleague, I switched from RedisToGo to openredis and these problems went away immediately.
You can't pass both a URL and an options hash to config.cache_store, because of this bug:
config.cache_store = :redis_store, resque_config[rails_env], { expires_in: 14.days }
If you pass a URL and an options hash, it ignores the URL and defaults to localhost, which is probably why you're seeing a timeout (I just had the same issue).
Instead, do something like this:
redis_uri = URI.parse(ENV["REDISTOGO_URL"])
config.cache_store = :redis_store, {
host: redis_uri.host,
port: redis_uri.port,
password: redis_uri.password,
namespace: "cache",
expires_in: 7.days
}