蓝天,小湖,湖水中一方小筑

Using Rails with Redis

I have met an issue recently that the Rails site always returns 502 error for some page. After some investigation, I have found that the problem is caused by a long time query of database, which exceeds the timeout value of unicorn configuration, then the unicorn worker process will be killed and the Nginx returns 502 to user.

So the solution for this kind prblem is to put the job into some background task, and use some other method to inform the frontend when job done. Finally I choose the Redis for this task.

First of all, the Redis server should be run on the server, I am using ubuntu on the server so the command is:

sudo apt-get install redis-server

After installion done, the server will be started as service in the server.

Then the Rails part. I am using a gem called resque for creating background jobs. I have followed the RailsCasts #271 to setup my project, and here is a brief instruction for Rails part:

First a rake task for resque it is needed, which is also listed in the rails casts site.

require "resque/tasks"

task "resque:setup" => :environment

Then create workers for the long time tasks in app/worker directory. I am using sleep method to simulate the long time task, and then the script will write some data into Rails cache. Here is the file content of app/worker/cache_writer.rb

class CacheWriter
  @queue = :rails_cache
  def self.perform(cache_key)
    sleep 10
    Rails.cache.write(cache_key, "foobar")
  end
end

After worker creation done, I need to update code in the controller to enqueue job to Redis. Now in the controller, I just need to enque the task to Redis queue with Resque.enqueue and return:

class TestCachesController < ApplicationController
  def index
    @foo = Rails.cache.read("foo")
    if @foo.nil?
      Resque.enqueue(CacheWriter, "foo")
    end
  end

  def show
  end
end

Now the task can be added to the queue, and we need worker to handle it. The bin/resque work will start a worker process, and the parameter --queues= or --queue= can be added to specify the working queue. I have copied some code from this page to make the rake can start/stop the workers.