Hello there!

I'm Shubham Bansal

Hello there, I am Shubham Bansal.

I live in Chicago with my Wife and Daughter.

I like Programming, Reading, Travel and Squash. I am @shubhambansal on twitter.

Sending emails using Sidekiq

Sidekiq is an awesome gem written by Mike Perham used for processing background jobs in Ruby. Sidekiq uses threads to process multiple jobs within the same process at the same time. It is highly compatible with Resque as it shares the exact same message format as Resque.

I have been playing around with Sidekiq for a while and I almost always use it for sending emails from my application. Most of the emails sent from an application are notifications about a certain events and they should always be sent asynchronously. Sending emails asynchronously will also reduce your application response time.

Sidekiq Dependencies

Sidekiq uses Redis for data storage and holds all the job data. You can install redis using Homebrew on a Mac.

$ brew install redis
 # To have launchd start redis at login:
$ ln -sfv /usr/local/opt/redis/*.plist ~/Library/LaunchAgents
 # Then to load redis now:
$ launchctl load ~/Library/LaunchAgents/homebrew.mxcl.redis.plist
 # Or, if you don't want/need launchctl, you can just run:
$ redis-server /usr/local/etc/redis.conf

To install redis on an ubuntu machine follow the instructions here or here.

Sidekiq Installation

Just add the gem to your Gemfile. The sinatra gem is required to access the web console for monitoring the state of the installation.

gem 'sinatra', '>= 1.3.0', :require => nil
gem 'sidekiq'

Start sidekiq from the root directory of your Rails app.

$ bundle exec sidekiq

Make sure you’re redis server is up and running as well.

Asynchronus emails using sidekiq

The easiest way to send an email asynchronously is by using the Delayed Extension. You can specify a delay interval as well. The email will be sent using a separate thread without blocking the main execution thread.

def invite_person
  UserMailer.delay.invite_person(@user.id)
  #UserMailer.delay_for(5.minutes).invite_person(@user.id)
end

Another way is to create your own worker process. Create the app/workers directory within your Rails application and add a new worker object there. Make sure that the Worker object includes Sidekiq::Worker module.

class EmailSender
  include Sidekiq::Worker
  def perform(id)
    UserMailer.invite_person(id).deliver
  end
end

Finally replace your call to the ActionMailer with the newly created EmailSender.

def invite_person
  EmailSender.perform_async(@user.id)
end

Its not a good idea to save state in Sidekiq. Only pass simple identifiers to it and load the actual objects at the time of processing. This would prevent issues caused by stale objects as well.

#Deployment

The deployment setup for Sidekiq is pretty straight forward. Just add the following to you Capistrano deploy.rb file.

require "sidekiq/capistrano"

This should be sufficient for setting up and starting Sidekiq on the each application server. You should also read the rake file which makes this magic happen.

However, for more advanced configuration, please refer to the document here. If you would like to separate the servers on which you want to run Sidekiq workers, you would have to specifiy that in your capistrano deploy config.

Personally, I am super happy with the performance and feature set of Sidekiq. It has everything I need to process background jobs right now. There are some other great libraries like Resque, Stalker, Delayed Job for processing background jobs. Check them out as well and pick the one that works for you.