Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

rails sidekiq cannot find the created record

I am using sidekiq to run some job after creating a record. when the job tries to find the record with the created ID, there are random cases where it raises a RecordNotFound. how can this be possible?

class Person
  def self.test_create
    p = Person.create(
      name: 'test'
    )

    p.run_on_sidekiq
  end

  def run_on_sidekiq
    PersonJob.perform_async(self.id)
  end
end

# Sidekiq runs on other server.
class PersonJob
  def perform(id)
    person = Person.find(id) # sometimes raises RecordNotFound!

    # ...
    # do something
    # ...
  end
end

EDIT: as per Alexei's answer, this case was more related with Sidekiq. edited the question to add more detail on Sidekiq usage.

like image 597
Yeonho Avatar asked Nov 09 '15 07:11

Yeonho


2 Answers

This is a common case when you're using Sidekiq in after_create hooks. What is actually going on is that Sidekiq starts working before the transaction has been finished, that's why it can't find model in database (and also because it's so blazingly fast). What you need to do is to change your after_create hook to after_commit which ensures that transaction has been finished.

If you show your exact code that uses Sidekiq, I can elaborate more about your specific usage.

UPDATE: This is strange, your current code should be fine, since calling save/destroy already gets wrapped in a transaction.

One reason I can think about is validation error. If your Person.create call fails in some way, you'll get back an instance of Person where id would be nil. This way, Sidekiq will try to find a record with id=nil and will throw an error.

like image 138
Alexey Shein Avatar answered Nov 18 '22 01:11

Alexey Shein


create doesn't guarantee also it will roll-back silently, if there are any errors.

create! would raise an exception on failing condition.

What I would think the ideal way to call your method is to check if object is persisted? against database.

 def test_create
   person = Person.create(name: 'test')
   person.some_method if person.persisted?
 end

Other way:

person.some_method unless person.errors.any?
like image 43
Nithin Avatar answered Nov 18 '22 02:11

Nithin