A gem for monitoring Sidekiq worker executions with run tracking, success/failure metrics, metadata capture, and optional tenant scoping.
- Track individual worker executions (runs) with timing, status, and metadata
- Maintain summary statistics per worker (total runs, success/failure counts)
- Optional tenant/organization scoping for multi-tenant applications
- Configurable table names and logging
- Rails generators for easy setup
Add this line to your application's Gemfile:
gem "worker_monitoring", path: "../worker_monitoring"
# Or for git-based installation:
# gem "worker_monitoring", git: "https://github.com/Cloverhound/worker_monitoring"Then run the install generator:
# Without tenant scoping
rails generate worker_monitoring:install
# With tenant scoping
rails generate worker_monitoring:install --tenant-class=Organization --tenant-foreign-key=organization_idRun migrations:
rails db:migrateConfigure the gem in config/initializers/worker_monitoring.rb:
WorkerMonitoring.configure do |config|
# Tenant/organization scoping
config.tenant_class = "Organization" # Set to nil to disable
config.tenant_foreign_key = :organization_id
# Table names
config.worker_table_name = :monitored_workers
config.run_table_name = :monitored_worker_runs
# Logger
config.logger = Rails.logger
# Custom log context formatter
config.log_context_formatter = ->(tenant) { " - #{tenant.name} (#{tenant.id})" }
endFor workers that operate on a specific tenant/organization:
class SyncUsersWorker
include Sidekiq::Worker
include WorkerMonitoring::TenantMonitoring
def perform(organization_id)
with_tenant_monitoring("Sync Users", organization_id) do |organization, context|
# Your work here...
users = sync_users(organization)
# Add metadata to the run
context[:run_metadata][:users_synced] = users.count
context[:run_metadata][:api_calls] = 5
end
end
endFor workers that don't belong to a specific tenant:
class CleanupWorker
include Sidekiq::Worker
include WorkerMonitoring::Monitorable
def perform
context = init_monitoring("Cleanup Old Records", nil)
begin
# Your work here...
deleted_count = cleanup_records
context[:run_metadata][:records_deleted] = deleted_count
complete_monitoring(context, WorkerMonitoring::MonitoredWorkerRun::STATUS_SUCCESS)
rescue StandardError => e
complete_monitoring(context, WorkerMonitoring::MonitoredWorkerRun::STATUS_FAILED, error: e)
raise
ensure
finalize_monitoring(context)
end
end
endTracks a worker type (optionally scoped to a tenant):
worker = WorkerMonitoring::MonitoredWorker.find_by(job: "Sync Users", organization_id: 1)
worker.last_status # => "success"
worker.last_execution_time # => 2025-01-05 10:30:00
worker.total_runs_count # => 42
worker.success_runs_count # => 40
worker.failed_runs_count # => 2
worker.success_rate # => 95.24
worker.average_duration # => 1234 (ms)
worker.recent_runs(limit: 5) # => [MonitoredWorkerRun, ...]Tracks individual executions:
run = WorkerMonitoring::MonitoredWorkerRun.last
run.status # => "success"
run.job # => "Sync Users" (delegated from monitored_worker)
run.duration_ms # => 1234
run.metadata # => { "users_synced" => 100, "api_calls" => 5 }
run.error_context # => nil (or { "message" => "...", "class" => "...", "backtrace" => [...] })WorkerMonitoring::MonitoredWorkerRun::STATUS_SUCCESS # => "success"
WorkerMonitoring::MonitoredWorkerRun::STATUS_FAILED # => "failed"
WorkerMonitoring::MonitoredWorkerRun::STATUS_SKIPPED # => "skipped"
WorkerMonitoring::MonitoredWorkerRun::STATUS_RUNNING # => "running"After checking out the repo, run bin/setup to install dependencies.
The gem is available as open source under the terms of your license.