Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use Redis with Rails?

I want really fast caching and hence I am using redis. I think I am doing it wrong and hence am facing issues.

Here is what I am doing everytime I used redis. In my controller file, user.rb

def online?
  !Redis.new.get("#{self.auth_token}").nil?
end

Then for checking if users are online or not, I am using this,

@users_ol = User.where(:id => @id).select(&:online?)

This fetches me list of all the users currently online. This works well in localhost but breaks when running on server.

My questions are

  • How to debug and know if this problem is being caused by redis or not?
  • What is the proper way to use Redis in Rails?
  • Does redis need extra confguration for server (nginx) to work properly in production?

You can comment with the link answering theses questions (fine with me) Thanks in advance

like image 733
Vaibhav Maheshwari Avatar asked Jun 22 '18 10:06

Vaibhav Maheshwari


2 Answers

You are making redis connection for each controller request. This will be a disaster on scale. Ideally, you should open one connection for one rails instnace. To do that, create config/initializers/redis.rb

redis_host = Rails.application.secrets.redis && Rails.application.secrets.redis['host'] || 'localhost'
redis_port = Rails.application.secrets.redis && Rails.application.secrets.redis['port'] || 6379

# The constant below will represent ONE connection, present globally in models, controllers, views etc for the instance. No need to do Redis.new everytime
REDIS = Redis.new(host: redis_host, port: redis_port.to_i)

See the application secrets part, there I'm specifying the configuration to be used, and exposing the host and port for production and other environments in their own secrets. This enables me to have dynamic control of redis host and port based on environment, and fallback to localhost:6379 (Default) on local.

def online?
  !Redis.new.get("#{self.auth_token}").nil?
end

should become

def online?
  REDIS.get("#{self.auth_token}").present?
end

How to debug and know if this problem is being caused by redis or not?

See the Rails server exception's log to see what breaks and why. Use gem like exception_notification to send you mails when exception is triggered on different envs.

What is the proper way to use Redis in Rails?

See the initial part of this answer. Make one connection, use Rails secrets or environment variables to expose host, port. Totally depends on how and where you setup Redis instance.

Does redis need extra confguration for server (nginx) to work properly in production?

Doesn't need anything special for nginx. You just have to configure it in your application and make sure you are able to connect.

like image 109
kiddorails Avatar answered Oct 20 '22 12:10

kiddorails


In production, I am using Kubernetes where the Redis URL is redis://redis:6379/0.

In my Rails developer environment, in Docker, the Redis URL is also as above but in my Rails on localhost, outside of Docker, the Redis url is redis://localhost:6379.

He accepted answer makes a good point about setting Redis.new in the initializer to establish a single connection.

The solution in the accepted answer won't work if you use Rails locally and in Docker in the development environment. The solution for me is to use the code below in my config/initializers/redis.rb file:

redis_url = ENV.fetch("REDIS_URL")

REDIS = Redis.new(url: redis_url)

Then in my controller I use the following code:

REDIS.incr "page hits"
@page_hits = REDIS.get "page hits"

I use .env_file to set REDIS_URL in Docker and .rbenv-vars in the parent directory of my Rails application to set REDIS_URL to run Rails on localhost.

For Kubernetes, I set REDIS_URL in the environment section in my rails_deploy.yaml file.

like image 3
markhorrocks Avatar answered Oct 20 '22 11:10

markhorrocks