Home > Software engineering >  Rails 5 - Sidekiq worker shows job done but nothing happens
Rails 5 - Sidekiq worker shows job done but nothing happens

Time:12-23

I'm using Sidekiq for delayed jobs with sidekiq-status and sidekiq-ent gems. I've created a worker which is reponsible to update minor status to false when user is adult and has minor: true. This worker should be fired every day at midnight ET. Like below:

#initializers/sidekiq.rb
config.periodic do |mgr|
  # every day between midnight 0 5 * * *
  mgr.register("0 5 * * *", MinorWorker)
end

#app/workers/minor_worker.rb
class MinorWorker
  include Sidekiq::Worker

  def perform
    User.adults.where(minor: true).remove_minor_status
  rescue => e
    Rails.logger.error("Unable to update minor field. Exception: #{e.message} : #{e.backtrace.join('\n')}")
  end
end

#models/user.rb
class User < ApplicationRecord
  scope :adults,          -> { where('date_of_birth <= ?', 18.years.ago) }

  def self.remove_minor_status
    update(minor: false)
  end
end

No I want to check this on my local machine - to do so I'm using gem 'timecop' to timetravel:

#application.rb
config.time_zone = 'Eastern Time (US & Canada)'

#config/environments/development.rb
config.after_initialize do
  t = Time.local(2021, 12, 21, 23, 59, 0)
  Timecop.travel(t)
end

After firing up sidekiq by bundle exec sidekiq and bundle exec rails s I'm waiting a minute and I see that worker shows up:

2021-12-21T22:59:00.130Z 25711 TID-ovvzr9828 INFO: Managing 3 periodic jobs
2021-12-21T23:00:00.009Z 25711 TID-ovw69k4ao INFO: Enqueued periodic job SettlementWorker with JID ddab15264f81e0b417e7dd83 for 2021-12-22 00:00:00  0100
2021-12-21T23:00:00.011Z 25711 TID-ovw69k4ao INFO: Enqueued periodic job MinorWorker with JID 0bcd6b76d6ee4ff9e7850b35 for 2021-12-22 00:00:00  0100

But it didn't do anything, the user's minor status is still set to minor: true:

2.4.5 :002 > User.last.date_of_birth
 => Mon, 22 Dec 2003
2.4.5 :001 > User.last.minor
 => true

Did I miss something?

EDIT

I have to add that when I'm trying to call this worker on rails c everything works well. I've got even a RSpec test which also passes:

RSpec.describe MinorWorker, type: :worker do
  subject(:perform) { described_class.new.perform }

  context 'when User has minor status' do
    let(:user1) { create(:user, minor: true) }

    it 'removes minor status' do
      expect { perform }.to change { user1.reload.minor }.from(true).to(false)
    end

    context 'when user is adult' do
      let(:registrant2) { create(:registrant) }

      it 'not change minor status' do
        expect(registrant2.reload.minor).to eq(false)
      end
    end
  end
end

CodePudding user response:

Since this is the class method update won't work

def self.remove_minor_status
  update(minor: false)
end

Make use of #update_all

def self.remove_minor_status
  update_all(minor: false)
end

Also, I think it's best practice to have some test cases to ensure the working of the methods.

As of now you can try this method from rails console and verify if they actually work

test "update minor status" do
  user = User.create(date_of_birth: 19.years.ago, minor: true)
  User.adults.where(minor: true).remove_minor_status

  assert_equal user.reload.minor, false
end

CodePudding user response:

I think you need to either do update_all or update each record by itself, like this:

User.adults.where(minor: true).update_all(minor: false)

or

class MinorWorker
  include Sidekiq::Worker

  def perform
    users = User.adults.where(minor: true)
    users.each { |user| user.remove_minor_status }
  rescue => e
    Rails.logger.error("Unable to update minor field. Exception: #{e.message} : #{e.backtrace.join('\n')}")
  end
end

You may also want to consider changing update to update! so it throws an error if failing to be caught by your rescue in the job:

def self.remove_minor_status
  update!(minor: false)
end
  • Related