I use Redis caching in my Rails app:
config.cache_store = :redis_store, redis_url
When I push my Rails app straight to Heroku, it is deployed successfully. When using Travis, the Heroku deploy step fails because the asset precompilation attempts to connect to Redis.
Running: rake assets:precompile
rake aborted!
ArgumentError: invalid uri scheme ''
/tmp/build_7c5f167bf750cb2986dbb9c3510ea11e/vendor/bundle/ruby/2.1.0/gems/redis-3.2.0/lib/redis/client.rb:390:in `_parse_options'
I have tried various things: overriding RedisStore methods using rake tasks, moving the cache_store instantiation to the initialization phase, using Docker instead of sudo, changing Heroku build strategy and other travis.yml configurations etc.
I don't want to precompile locally, and I'd rather not change caching solution. Many other apps running on the cedar-14 stack use a very similar setup so the issue seems a bit peculiar.
Any suggestions how to resolve this Travis+Heroku deploy issue?
In my case, I solved this by changing the redis init to:
REDIS = Redis.new(:url => redis_url_string)
where previously I was parsing the URI and passing in the arguments as:
uri = URI.parse(redis_url)
REDIS = Redis.new(:host => uri.host, :port => uri.port, :password => uri.password, :scheme => uri.scheme)
I wonder if the cache store init has a similar init implementation for redis (I haven't checked the source there).
We solved the problem by overriding the Redis::Store initialization. When using Travis to trigger the Heroku deploy, Redis Store tries to connect to Redis. This is probably due to the current version (Nov 2013) of the Redis Store gem not being compatible with the current asset pipeline implementation. The reason why this works when pushing straight to Heroku is unclear. It could be related to the order that assets are compiled, when using the Heroku build strategies as specified in the travis.yml file. Perhaps these issues will be resolved in future Redis Store versions.
This is the rake task used to avoid loading Redis when using Redis Store as cache store (lib/assets/tasks/assets.rake):
pt = Rake::Task['assets:environment']
Rake.application.send(:eval, "@tasks.delete('assets:environment')")
namespace :assets do
task :environment do
class Redis
class Store
def initialize(options = { })
puts ”Do nothing"
end
end
def initialize(options = { })
puts ”Do nothing"
end
end
pt.execute
end
end
This is not a very elegant solution, but it does the trick for now. Consider changing the caching solution instead.