sidekiq icon indicating copy to clipboard operation
sidekiq copied to clipboard

Unclear how to add automated test ensuring that Periodic Jobs configuration can be processed

Open f1sherman opened this issue 3 years ago • 4 comments

Ruby version: 3.1.2 Rails version: 7.0.3.1 Sidekiq / Pro / Enterprise version(s): 6.5.1/ 5.5.1 / 2.5.1

We recently had an issue with Periodic Jobs where a typo in a single entry of our Periodic Jobs configuration caused our whole configuration to not be able to be processed. I'm looking for a way that we could add automated testing to ensure that our configuration can be processed. We've followed the testing instructions in https://github.com/mperham/sidekiq/wiki/Ent-Periodic-Jobs and no error is raised with our bad configuration.

The typo itself was that we passed a symbol to the tz: argument instead of a ActiveSupport::TimeZone instance. The error we observed was the following:

  WARN: NoMethodError: undefined method `now' for :pt:Symbol
4
5      def next_occurrence(now = @src.now, time_now = Time.now)
6                                    ^^^^
  WARN: /app/vendor/bundle/ruby/3.1.0/gems/sidekiq-ent-2.5.1/lib/sidekiq-ent/periodic/static_loop.rb:26:in `next_occurrence'

f1sherman avatar Aug 10 '22 19:08 f1sherman

Can you give me the entire error backtrace?

mperham avatar Aug 10 '22 20:08 mperham

@mperham sure thing, here you go:

/app/vendor/bundle/ruby/3.1.0/gems/sidekiq-ent-2.5.1/lib/sidekiq-ent/periodic/static_loop.rb:26:in `next_occurrence'
/app/vendor/bundle/ruby/3.1.0/gems/sidekiq-ent-2.5.1/lib/sidekiq-ent/periodic/config.rb:107:in `block in queue_for'
/app/vendor/bundle/ruby/3.1.0/gems/sidekiq-ent-2.5.1/lib/sidekiq-ent/periodic/config.rb:106:in `each'
/app/vendor/bundle/ruby/3.1.0/gems/sidekiq-ent-2.5.1/lib/sidekiq-ent/periodic/config.rb:106:in `queue_for'
/app/vendor/bundle/ruby/3.1.0/gems/sidekiq-ent-2.5.1/lib/sidekiq-ent/periodic/config.rb:99:in `finish!'
/app/vendor/bundle/ruby/3.1.0/gems/sidekiq-ent-2.5.1/lib/sidekiq-ent/periodic/manager.rb:56:in `persist'
/app/vendor/bundle/ruby/3.1.0/gems/sidekiq-ent-2.5.1/lib/sidekiq-ent/periodic.rb:95:in `block (2 levels) in <top (required)>'
/app/vendor/bundle/ruby/3.1.0/gems/sidekiq-6.5.1/lib/sidekiq/component.rb:56:in `block in fire_event'
/app/vendor/bundle/ruby/3.1.0/gems/sidekiq-6.5.1/lib/sidekiq/component.rb:55:in `each'
/app/vendor/bundle/ruby/3.1.0/gems/sidekiq-6.5.1/lib/sidekiq/component.rb:55:in `fire_event'
/app/vendor/bundle/ruby/3.1.0/gems/sidekiq-ent-2.5.1/lib/sidekiq-ent/senate.rb:85:in `stage_coup!'
/app/vendor/bundle/ruby/3.1.0/gems/sidekiq-ent-2.5.1/lib/sidekiq-ent/senate.rb:93:in `cycle'
/app/vendor/bundle/ruby/3.1.0/gems/sidekiq-6.5.1/lib/sidekiq/component.rb:8:in `watchdog'
/app/vendor/bundle/ruby/3.1.0/gems/sidekiq-6.5.1/lib/sidekiq/component.rb:17:in `block in safe_thread'

f1sherman avatar Aug 10 '22 21:08 f1sherman

I guess I'm unclear on something: why doesn't the developer test this by simply starting Sidekiq? It sounds like someone changed the periodic configuration and those changes were pushed straight to production without any staging or integration testing. Is your deployment process "if CI is green, push to production"?

mperham avatar Aug 10 '22 21:08 mperham

@mperham you're right, this definitely could be caught by manual testing. Just looking for a way to catch it via automated testing if that's possible.

f1sherman avatar Aug 10 '22 22:08 f1sherman

@f1sherman We only enable certain crons in prod, so we had issues similar. Similar to the wiki guide, we have a class

class PeriodicJobsRegistration

  def self.call(mgr)
    # ...
    mgr.register('0 7 * * *', 'OurDailyWorker') # Daily at 7:00AM UTC
  end

and a verifier class defined at the top of our rspec periodic_jobs_registration_spec.rb

class PeriodicJobVerifier
  # raise an error to fail the spec.
  def register(_sched, klass, args: nil, **_rest)
    # Will raise if the constant is not defined.
    klass_constant = klass.constantize if klass.is_a?(String)

    raise 'Passing constants to periodic job registrations is deprecated, pass a String' if klass.is_a?(Class)

    raise 'Worker must include Sidekiq::Worker or inherit ApplicationWorker' unless klass_constant.ancestors.include?(Sidekiq::Worker)
  end
end
# ...
RSpec.describe PeriodicJobsRegistration do
  it 'does not raise an error for any job registration' do
    expect { described_class.call(PeriodicJobVerifier.new) }.not_to raise_error
  end
end

You could add a check in the verifier that the :tz arg is an ActiveSupport::TimeZone instance.

BobbyMcWho avatar Sep 28 '22 13:09 BobbyMcWho

@BobbyMcWho thank you, that’s helpful. I think what would be more useful IMO would be a way to test that Sidekiq can process our configuration successfully. That way if there are any other issues that might cause Sidekiq to fail to process the config we could catch it in automated testing.

f1sherman avatar Sep 28 '22 14:09 f1sherman

Unfortunately I don't have a better solution than "start Sidekiq" right now.

mperham avatar Jan 11 '23 16:01 mperham