How to Monitor Your Sidekiq Workers with Vigilmon
Sidekiq is the most popular background job processor for Ruby on Rails applications — used for sending emails, processing webhooks, generating reports, and handling anything that shouldn't block a request. When Sidekiq goes down, it goes down quietly: no 500 errors, no user-facing failures — just a growing job backlog and eventually, users wondering why nothing is happening.
This guide shows how to monitor Sidekiq with Vigilmon — from worker health to queue depth and scheduled job verification.
How Sidekiq Fails
- Process crash — Sidekiq exits; Rails continues serving requests normally while jobs pile up
- Redis connection lost — Sidekiq can't connect to Redis; jobs queue locally and eventually drop
-
Dead job explosion — failed jobs that exceed
max_retriesaccumulate in the dead set - Cron job drift — Sidekiq-Cron or Sidekiq-Scheduler stops firing scheduled jobs
- Memory exhaustion — Sidekiq worker OOMs after processing large jobs; the process exits silently
Step 1: Add a Heartbeat Job to Sidekiq
The most reliable Sidekiq health check is a scheduled job that pings a heartbeat URL:
# app/jobs/health_heartbeat_job.rb
class HealthHeartbeatJob < ApplicationJob
queue_as :health
def perform
heartbeat_url = ENV.fetch('VIGILMON_HEARTBEAT_URL', nil)
return unless heartbeat_url
require 'net/http'
uri = URI(heartbeat_url)
Net::HTTP.get(uri)
rescue => e
Rails.logger.error("Health heartbeat failed: #{e.message}")
end
end
Schedule it with Sidekiq-Cron:
# config/schedule.yml (sidekiq-cron)
health_heartbeat:
cron: '* * * * *' # Every minute
class: 'HealthHeartbeatJob'
queue: health
In Vigilmon, create a Heartbeat monitor with:
- Expected interval: 1 minute
- Grace period: 90 seconds
If the heartbeat stops, either Sidekiq is down or the scheduler stopped.
Step 2: Expose a Sidekiq Health Endpoint in Rails
Add a Rails route that checks Sidekiq's status:
# config/routes.rb
get '/health/sidekiq', to: 'health#sidekiq'
# app/controllers/health_controller.rb
class HealthController < ApplicationController
skip_before_action :authenticate_user!, only: [:sidekiq]
def sidekiq
# Check Redis connection
Sidekiq.redis { |conn| conn.ping }
# Get queue stats
stats = Sidekiq::Stats.new
queue_size = Sidekiq::Queue.new.size
dead_size = Sidekiq::DeadSet.new.size
if dead_size > 100
render json: { status: 'degraded', dead_jobs: dead_size }, status: :service_unavailable
elsif queue_size > 10_000
render json: { status: 'degraded', queue_depth: queue_size }, status: :service_unavailable
else
render json: {
status: 'ok',
queue_size: queue_size,
dead_jobs: dead_size,
processed: stats.processed,
failed: stats.failed
}, status: :ok
end
rescue Redis::CannotConnectError => e
render json: { status: 'error', error: e.message }, status: :service_unavailable
end
end
Monitor https://your-app.com/health/sidekiq with Vigilmon.
Step 3: Monitor Sidekiq Web UI
Sidekiq ships with a Rack-based web UI for monitoring queue status:
# config/routes.rb
require 'sidekiq/web'
Sidekiq::Web.use(Rack::Auth::Basic) { |u, p| u == 'admin' && p == ENV['SIDEKIQ_WEB_PASSWORD'] }
mount Sidekiq::Web, at: '/sidekiq'
Monitor https://your-app.com/sidekiq/ — it returns 200 when Sidekiq is running and Redis is reachable.
Step 4: Monitor Queue Depth via a Cron Heartbeat
For precise queue depth monitoring, add a system cron:
#!/bin/bash
# sidekiq-queue-check.sh
cd /app
DEPTH=$(bundle exec rails runner \
"puts Sidekiq::Queue.new.size" 2>/dev/null)
MAX_DEPTH=${MAX_QUEUE_DEPTH:-5000}
if [ -n "$DEPTH" ] && [ "$DEPTH" -lt "$MAX_DEPTH" ]; then
curl -sf "$VIGILMON_HEARTBEAT_URL" > /dev/null
fi
*/5 * * * * www-data /usr/local/bin/sidekiq-queue-check.sh
Sidekiq Monitoring Coverage Table
| Monitor Type | Target | Alert Condition |
|---|---|---|
| Heartbeat | Scheduled health job | No ping in > 90 seconds |
| HTTP(S) |
/health/sidekiq Rails endpoint |
Status != 200 |
| HTTP(S) | Sidekiq Web UI /sidekiq/
|
Status != 200 |
| Heartbeat | Queue depth cron | No ping if queue > 5000 |
Common Sidekiq Failure Scenarios
Deployment kills workers: During a Rails deploy, Sidekiq processes are restarted. Without a proper warm restart, in-flight jobs may fail. The heartbeat gap during deploy surfaces this.
Redis OOM: Redis evicts keys when memory is full. Sidekiq jobs are lost silently. The heartbeat job enqueue fails — Vigilmon fires an alert.
Dead job explosion: A broken API causes 1000 jobs to fail over an hour. The /health/sidekiq endpoint returns 503 (dead_jobs > 100). Vigilmon alerts within 60 seconds.
Conclusion
Sidekiq is essential infrastructure for Rails apps, but it fails silently. A heartbeat job combined with a health endpoint gives you both the early warning (heartbeat stops) and the diagnosis (endpoint explains why).
Top comments (0)