The sidekiq-scheduler gem is an extension to sidekiq that pushes jobs in a scheduled way, mimicking cron utility.
It is a really usefull gem I like to use on every project that requires recurring jobs. It is also quite easy to set up once installed in your app. Most of the time, I require the gem in a sidekiq.rb
initializer so every jobs has access to this feature.
Once your set up is complete, you will have the ability to add schedules in your config/sidekiq.yml
file.
# config/sidekiq.yml example :schedule: hello_world: cron: '0 * * * * *' # Runs once per minute, could also be 'every: 1 minutes' class: HelloWorld
I really put an emphasis to test every feature that I code in an app. This article is about implementing the corresponding tests for the :schedule: part on this file. Imagine that you change the name of a recurring job and forget to reflect the change in this file? Or you messed up your cron syntax? Well you might not see it after some time, implementing automatic testing with RSpec will remedy to that.
There are 3 things I would like to test in the example above:
- The cron syntax should be correct
- The job the task is calling should exist
- The task name should be similar to the job name
Testing the cron syntax can be achieved thanks to 'fugit' which is a dependency of sidekiq-scheduler that analyze cron syntax, the 2 remaining things to test are pretty straightforward.
It basically looks like that:
# Sidekiq-scheduler uses 'fugit' dependency under the hood to evaluate cron schedules require "fugit" RSpec.describe "Sidekiq Scheduler" do sidekiq_file = File.join(Rails.root, "config", "sidekiq.yml") scheduled_jobs = YAML.load_file(sidekiq_file)[:schedule] scheduled_jobs.each do |task_name, task_config| job_class = task_config["class"] cron = task_config["cron"] || task_config["every"] || task_config["at"] || task_config["in"] describe "#{task_name}" do it "has a correct cron syntax" do expect { Fugit.do_parse(cron) }.not_to raise_error end it "is calling an existing job (#{job_class})" do expect { job_class.constantize }.not_to raise_error end it "has a correct name related to the called job" do expect(task_name + "_job").to eq(job_class.underscore) end end end end
Resources:
- A nice Dev.to article that inspired me for setting up these tests https://dev.to/pashagray/how-to-rspec-your-sidekiq-scheduler-5hgo?signin=true