How to monitor Sidekiq: A working example

Updated . Posted . Visible to the public.

In order to have monitoring for Sidekiq (like queue sizes, last run of Sidekiq) your application should have a monitoring route which returns a json looking like this:

{
  "sidekiq": {
    "totals": {
      "failed": 343938,
      "processed": 117649167
    },
    "recent_history": {
      "failed": {
        "2016-11-06": 1,
        "2016-11-07": 46,
        "2016-11-08": 0,
        "2016-11-09": 0,
        "2016-11-10": 0
      },
      "processed": {
        "2016-11-06": 230653,
        "2016-11-07": 230701,
        "2016-11-08": 230645,
        "2016-11-09": 230645,
        "2016-11-10": 163385
      }
    },
    "queue_sizes": {
      "dead": 0,
      "retries": 0,
      "monitoring": 0,
      "low_priority": 0,
      "mails": 0,
      "default": 0,
      "elasticsearch": 0,
      "high_priority": 0,
      "file_upload": 0,
      "scheduled": 0
    },
    "active_workers": 0
  },
  "timestamps": {
    "sidekiq_performed": "2016-11-10 17:51:03",
    "whenever_ran": "2016-11-10 17:51:02",
    "requested": "2016-11-10 17:56:45"
  }
}

Our friends from bitcrowd built a gem for it https://github.com/bitcrowd/sidekiq_monitoring Show archive.org snapshot .

Manual steps

In your application you need - at least - the following:

A controller rendering the monitoring output as JSON

class MonitoringController < ApplicationController

  def status
    data = {
      timestamps: {
        whenever_ran: Redis.current.get('monitoring:timestamp:whenever_ran'),
        sidekiq_performed: Redis.current.get('monitoring:timestamp:sidekiq_performed'),
        requested: Time.now.to_s(:db),
      },
      sidekiq: {
        active_workers: sidekiq_stats.workers_size,
        queue_sizes: sidekiq_queue_sizes,
        recent_history: {
          processed: sidekiq_history.processed,
          failed: sidekiq_history.failed
        },
        totals: {
          processed: sidekiq_stats.processed,
          failed: sidekiq_stats.failed
        }
      }
    }

    render json: data
  end

  private

  def sidekiq_stats
    @sidekiq_stats ||= Sidekiq::Stats.new
  end

  def sidekiq_history
    @sidekiq_history ||= Sidekiq::Stats::History.new(5)
  end

  def sidekiq_queue_sizes
    queue_sizes = sidekiq_stats.queues

    queue_sizes.merge({
      scheduled: sidekiq_stats.scheduled_size,
      retries: sidekiq_stats.retry_size,
      dead: sidekiq_stats.dead_size
    })
  end

end

A cronjob that puts a simple job to Sidekiq to ensure it is running

Put this into config/schedule.rb (if you're using whenever). Use whatever else to build the Cronjob on your server.

job_type :enqueue, 'cd :path && :environment_variable=:environment bundle exec bin/enqueue :task'

every 5.minutes do
  enqueue 'monitoring'
end

The worker itself should live in app/workers/cron_workers/monitoring_worker.rb and look like that:

require_relative 'base_worker'

class CronWorkers::MonitoringWorker < CronWorkers::BaseWorker

  def perform
    Redis.current.set('monitoring:timestamp:sidekiq_performed', Time.now.to_s(:db))
  end

end

And finally you need this in bin/enqueue:

#!/usr/bin/env ruby

require_relative '../config/initializers/sidekiq'

def enqueue(worker_class, args = [])
  job = worker_class.sidekiq_options.merge('args' => args, 'class' => worker_class.to_s)
  Sidekiq::Client.push(job)
end

case ARGV.shift
when 'monitoring'

  require_relative '../config/initializers/redis'
  require_relative '../app/workers/cron_workers/monitoring_worker'

  Redis.current.set 'monitoring:timestamp:whenever_ran', Time.now.strftime('%Y-%m-%d %H:%M:%S')

  enqueue(CronWorkers::MonitoringWorker)

end

Finally - and this is propably most important - you need a monitoring system (Icinga, Nagios, etc.) that checks the JSON output generated with the stuff above.

We built this into http://railscomplete.de Show archive.org snapshot .

Profile picture of Thomas Eisenbarth
Thomas Eisenbarth
Last edit
Michael Leimstädtner
License
Source code in this card is licensed under the MIT License.
Posted by Thomas Eisenbarth to makandra dev (2016-11-10 16:53)