Search code examples
ruby-on-railsrubyruby-on-rails-3sidekiq

Rails methods not initialized in time for worker


Earlier, I had posted this question – and thought it was resolved:

Rails background worker always fails first time, works second

However, after continuing with tests and development, the error is back again, but in a slightly different way.

I'm using Sidekiq (with Rails 3.2.8, Ruby 1.9.3) to run background processes, after_save. Below is the code for my model, worker, and controller.

Model:

class Post < ActiveRecord::Base

  attr_accessible :description, 
                  :name,
                  :key 

  after_save :process

  def process
    ProcessWorker.perform_async(id, key) if key.present?
    true
  end

  def secure_url
    key.match(/(.*\/)+(.*$)/)[1]
  end

  def nonsecure_url
    key.gsub('https', 'http')
  end

end

Worker:

class ProcessWorker
  include Sidekiq::Worker

  def perform(id, key)

    post = Post.find(id)
    puts post.nonsecure_url

  end
end     

(Updated) Controller:

def create
  @user = current_user
  @post = @user.posts.create(params[:post])
  render nothing: true
end

Whenever jobs are first dispatched, no matter the method, they fail initially:

undefined method `gsub' for nil:NilClass

Then, they always succeed on the first retry.

I've come across the following github issue, that appears to be resolved – relating to this same issue:

https://github.com/mperham/sidekiq/issues/331

Here, people are saying that if they create initializers to initialize the ActiveRecord methods on the model, that it resolves their issue.

To accomplish this, I've tried creating an initializer in lib/initializers called sidekiq.rb, with the following, simply to initialize the methods on the Post model:

Post.first

Now, the first job created completes successfully the first time. This is good. However, a second job created fails the first time – and completes upon retry... putting me right back to where I started.

This is really blowing my mind – has anyone had the same issue? Any help is appreciated.


Solution

  • Change your model callback from after_save to after_commit for the create action. Sometimes, sidekiq can initialize your worker before the model actually finishes saving to the database.

    after_commit :process, :on => :create