Skip to content

Instantly share code, notes, and snippets.

@Diasporism
Last active July 6, 2025 07:38
Show Gist options
  • Select an option

  • Save Diasporism/5631030 to your computer and use it in GitHub Desktop.

Select an option

Save Diasporism/5631030 to your computer and use it in GitHub Desktop.
How to configure Redis and Resque for your Rails app.
Redis and Resque
What this guide will cover: the code you will need in order to include Redis and Resque in your Rails app, and the process of creating a background job with Resque.
What this guide will not cover: installing Ruby, Rails, or Redis.
Note: As of this writing I am still using Ruby 1.9.3p374, Rails 3.2.13, Redis 2.6.11, and Resque 1.24.1. I use SQLite in development and Postgres in production.
Background jobs are frustrating if you've never dealt with them before. Over the past few weeks I've had to incorporate Redis and Resque into my projects in various ways and every bit of progress I made was very painful. There are many 'gotchas' when it comes to background workers, and documentation tends to be outdated or scattered at best.
The first thing you need to know about setting up Redis and Resque is that things change depending on your environment. You can get away with very minimal setup for a development environment, but production environments such as Heroku require extra steps which can often be frustrating to find.
So let's get started with the steps to configure Redis and Resque in your Rails app.
Setup
Add the following gems to your Gemfile and bundle:
```ruby
gem 'redis'
gem 'resque', require: 'resque/server'
gem 'resque-scheduler', :require => 'resque_scheduler' #this is a plugin for Resque that allows for easily scheduling delayed and scheduled jobs.
```
Note: 'resque-scheduler' is an optional plugin for rescue which allows you to easily setup scheduled jobs. You don't need it if you just want to move basic processes into background jobs and queue them up when certain events happen in your code.
Documentation for these gems:
https://github.com/resque/resque
https://github.com/bvandenbos/resque-scheduler
https://rubygems.org/gems/redis
Adding these gems to our gem file will give us the tools we need to interact with Redis and Resque in in our code.
From here we only need to add a couple lines of code in a few different files. Starting off, we will need rake tasks to start our schedules and workers.
Create a lib/tasks/resque.rb file and add the following to it:
```ruby
require 'resque/tasks'
require 'resque_scheduler/tasks'
namespace :resque do
task :setup do
require 'resque'
require 'resque_scheduler'
require 'resque/scheduler'
ENV['QUEUE'] = '*'
Resque.redis = 'localhost:6379' unless Rails.env == 'production'
Resque.schedule = YAML.load_file(File.join(Rails.root, 'config/resque_scheduler.yml'))
end
end
Resque.after_fork = Proc.new { ActiveRecord::Base.establish_connection } #this is necessary for production environments, otherwise your background jobs will start to fail when hit from many different connections.
desc "Alias for resque:work (To run workers on Heroku)"
task "jobs:work" => "resque:work"
```
If you aren't planning on using the resque-scheduler gem to create scheduled jobs you can cut line 50 out. The important bit is the line above it: "Resque.redis = 'localhost:6379' unless Rails.env == 'production'". This line tells Rails that we're running Redis on port 6379 (which is the Redis default) unless were running our app in production. Great, but where do we tell it to look if we are running in production? That's next.
Create a config/initializers/redis.rb file and add this to it:
```ruby
if Rails.env == 'production'
uri = URI.parse(ENV["REDISTOGO_URL"])
Resque.redis = Redis.new(:host => uri.host, :port => uri.port, :password => uri.password)
end
```
Notice that we are using an environment variable to hold our Redis url for us. Also note this block of code is only going to be run when our environment is production. That's fine because we already told Rails where to look for Redis for every other environment.
And finally, we need to actually set the environment variable. We do this in config/environments/production.rb by adding the following line inside the AppName::Application.configure block like so:
```ruby
YourAppNameHere::Application.configure do
ENV["REDISTOGO_URL"] = 'redis://redistogo:yourinfohere@something.redistogo.com:1234/'
#other stuff below
end
```
For the sake of clarity, the above Redis url is bogus. You'll need to replace it with a real one, which you can get for free by provisioning your Heroku app with Redis To Go Nano. When you visit your Redis To Go account, it should tell you what your url is.
And that's it for setup. Your app is now ready to create and schedule background jobs and workers in both production (assuming your using Heroku) and development.
Creating Background Jobs
Lets say we have a Rails app that sends an email out every time a user creates an account. If we had the code to send the email in our controller or model, the user would actually have to wait for Rails to send the email before he could continue after creating an account. This can be bad if the process of sending an email is slow (which it generally is).
Let's fix this by moving the code to send an email on account creation into a background job.
Create a app/jobs directory in your Rails app. This is where you will keep all your job classes. Inside the jobs directory, create an email_sender.rb file.
```ruby
class EmailSender
@queue = :emails_queue
def self.perform(params)
#code to send out emails
end
end
```
Stick all the of the code you had to send the email in the self.perform method (you can pass in any parameters you need into this method, it's just a Ruby method after all.) Then, in place of where you used to keep the code for sending emails, put this:
```ruby
Resque.enqueue(EmailSender, params[user_id: current_user.id])
```
Simple. Not only does it make your code look cleaner by moving responsibility out of controllers and models, but it also means that the code will execute in the background and the user will not have to wait for it to complete before he can continue.
Scheduling Jobs/Delayed Jobs
The resque-scheduler gem we included in the beginning of this guide allows for creating delayed jobs and scheduled jobs very easily. They also document the process of how to create them very well in their readme so I'll leave it to you to research that part: https://github.com/bvandenbos/resque-scheduler.
FIN
@jmodjeska
Copy link

Thanks for this! Perhaps this is a silly question, but is it safe to put the redistogo URL directly in production.rb if your project is under source control? The URL seems to contain a password. Strangely, Heroku's setup guide doesn't mention anything about the production environment, only dev. Thoughts?

@Theminijohn
Copy link

@jmodjeska, You don't have to add the redistogo url in prod. When provisioning Redis, heroku gives you the ENV variable which you can directly use .

@slucha
Copy link

slucha commented May 11, 2017

Thank you, great tutorial.
Job scheduler is running great on localhost and gets started in heroku production. Jobs show up in the scheduler ui but never get executed. Do I need to define somewhere that this job should start being executed somewhere, now I just have it run every: "60s"

@LucasPiffer
Copy link

LucasPiffer commented Oct 22, 2017

I named my lib/task as resque.rake instead resque.rb (Rails 5.1.4). Thanks for the excelent tutorial.

@bluengreen
Copy link

Yeah do NOT set the ENV VARS within the applications files. Silly. They are set in the environment. Hence the name environment variables. Setting environment variables this way is unsecure.

@iriscoopers
Copy link

Great gist. It helped me figure out some of the configuration on a Rails 5.1 app.

@fenec
Copy link

fenec commented Jul 16, 2018

FYI, you don't need this Resque.after_fork anymore with Rails > 5.2: rails/rails#31766

@toomanyjoes
Copy link

toomanyjoes commented Oct 9, 2019

Thanks for sharing your experience setting up resque! A couple of thoughts...

Instead of initializing resque for production inside config/initializers/redis.rb, which I would think should only hold global configurations, wouldn't it make more sense to initialize it for production in config/environments/production.rb so you don't have to wrap it in a conditional that checks if you're in the prod env?

This way you could do something like this instead:

if ENV["REDISTOGO_URL"].present?
    uri = URI.parse(ENV["REDISTOGO_URL"])
    Resque.redis = Redis.new(:host => uri.host, :port => uri.port, :password => uri.password)
end

You could also probably just use the above code in application.rb and make sure you have your env variable set to localhost:6379 on your development machine. This would also allow you to remove the line from your resque.rake file.

Resque.redis = 'localhost:6379' unless Rails.env == 'production'

so yes I agree with @bluengreen, no need to set the ENV var in config/environments/production.rb, just set it in the environment to the appropriate value. If you're using Heroku it should already be set for you during the provisioning of the Redis add on.

Lastly, Heroku now has Heroku Redis which may be a better alternative to Redis To Go.

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