Search code examples
ruby-on-railsherokurspecautomated-testssidekiq

How to automate testing successful boot of Sidekiq Process


We've had a couple of issues recently in our Rails 4 app that could have been prevented with a simple check to see that both the main app and a worker process correctly boot up our application.

Our Procfile for Heroku looks like so:

web: bundle exec unicorn -p $PORT -c config/heroku/unicorn.rb
sidekiq: bundle exec sidekiq -q high -q medium -q low

Right now, we run a very large test suite that takes 30 mins to complete, even when bisecting the suite across 10+ containers.

We use CircleCI and are considering adding a test like follows that simulates the Sidekiq bootup process.

require 'spec_helper'

RSpec.describe 'Booting processes' do

  context 'Sidekiq server' do
    it 'loads successfully' do
      boot_sidekiq_sequence = <<-SEQ
        require 'sidekiq/cli'
        Sidekiq::CLI.instance.environment = '#{ENV['RAILS_ENV']}'
        Sidekiq::CLI.instance.send(:boot_system)
      SEQ

      expect(system(%{echo "#{boot_sidekiq_sequence}" | ruby > /dev/null})).to be_truthy,
        "The Sidekiq process could not boot up properly. Run `sidekiq` to troubleshoot"
    end
  end
end

The problem with this is that:

  • It's not quite a complete test of our application boot process which would require reading from our Procfile (we also want to protect devs from making breaking changes there)
  • It's slow and would add approx 30 secs to our test runtime
  • It's a bit low-level for my liking.

What makes testing the Sidekiq boot process in particular challenging is that it will only exit if there is an exception on boot.

Can anyone recommend a better, faster, more thorough approach to automating this kind of test?


Solution

  • For integration testing, it's always best to run the process as close to production as possible, so bundle exec sidekiq .... I wouldn't use the CLI API to boot it in-process.

    I would first enqueue a special job which just does this:

    def perform
      puts "Sidekiq booted"
      Process.kill($$, TERM) # terminate ourselves
    end
    

    Then execute Sidekiq by running the binary and monitoring STDOUT. If you see /booted/ within 30 seconds, PASS. If you see nothing within 30 seconds, FAIL and kill the child.