14 KiB
skill, category, description
| skill | category | description |
|---|---|---|
| jobs | reference | Mission Control Jobs setup and authentication patterns |
Mission Control Jobs - Complete Setup Guide
Mission Control Jobs provides a production-ready web dashboard for monitoring and managing SolidQueue background jobs. This guide covers complete setup for development through production deployment with team access.
Quick Start
1. Add Gem
# Gemfile
gem "mission_control-jobs"
bundle install
2. Mount Engine with Authentication
# config/routes.rb
Rails.application.routes.draw do
# Production: Require admin authentication
if Rails.env.production?
authenticate :user, ->(user) { user.admin? } do
mount MissionControl::Jobs::Engine, at: "/jobs"
end
else
# Development/Staging: Open access or HTTP Basic Auth
mount MissionControl::Jobs::Engine, at: "/jobs"
end
end
3. Configure (Optional)
# config/initializers/mission_control.rb
MissionControl::Jobs.configure do |config|
# Job retention periods
config.finished_jobs_retention_period = 14.days # Default: 7 days
config.failed_jobs_retention_period = 90.days # Default: 30 days
# Filter sensitive arguments from dashboard display
config.filter_parameters = [:password, :token, :secret, :api_key]
end
4. Access Dashboard
Visit http://localhost:3000/jobs in your browser (development) or https://yourapp.com/jobs (production).
Production Authentication Patterns
Pattern 1: Devise Admin Users (Recommended)
# config/routes.rb
Rails.application.routes.draw do
authenticate :user, ->(user) { user.admin? } do
mount MissionControl::Jobs::Engine, at: "/jobs"
end
end
Requirements:
- User model with
admin?method oradminboolean field - Devise authentication already configured
Example User Model:
# app/models/user.rb
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
# Option 1: Boolean field
def admin?
admin # Assumes `admin` boolean column exists
end
# Option 2: Role-based
enum role: { user: 0, admin: 1, superadmin: 2 }
def admin?
admin? || superadmin?
end
end
Pattern 2: Custom Authentication Logic
# config/routes.rb
Rails.application.routes.draw do
authenticate :user, ->(user) { user.can_access_mission_control? } do
mount MissionControl::Jobs::Engine, at: "/jobs"
end
end
# app/models/user.rb
class User < ApplicationRecord
def can_access_mission_control?
admin? || role == "operations" || email.end_with?("@yourcompany.com")
end
end
Pattern 3: HTTP Basic Auth (Staging/Internal Tools)
# config/routes.rb
Rails.application.routes.draw do
# Add constraint for HTTP Basic Auth
constraints(->(req) { authenticate_mission_control(req) }) do
mount MissionControl::Jobs::Engine, at: "/jobs"
end
end
# config/application.rb or initializer
def authenticate_mission_control(request)
return true if Rails.env.development?
authenticate_or_request_with_http_basic do |username, password|
username == ENV['MISSION_CONTROL_USERNAME'] &&
password == ENV['MISSION_CONTROL_PASSWORD']
end
end
Set environment variables:
# .env or production secrets
MISSION_CONTROL_USERNAME=admin
MISSION_CONTROL_PASSWORD=secure_random_password_here
Pattern 4: IP Whitelist (Internal Networks)
# config/routes.rb
Rails.application.routes.draw do
constraints(->(req) { internal_ip?(req.remote_ip) }) do
mount MissionControl::Jobs::Engine, at: "/jobs"
end
end
# config/application.rb
def internal_ip?(ip)
allowed_ips = ENV.fetch('MISSION_CONTROL_IPS', '').split(',')
allowed_ips.include?(ip) || ip.start_with?('10.', '192.168.')
end
Pattern 5: Multi-Environment Configuration
# config/routes.rb
Rails.application.routes.draw do
case Rails.env
when "production"
# Production: Require admin user
authenticate :user, ->(user) { user.admin? } do
mount MissionControl::Jobs::Engine, at: "/jobs"
end
when "staging"
# Staging: HTTP Basic Auth
constraints(->(req) { authenticate_basic(req) }) do
mount MissionControl::Jobs::Engine, at: "/jobs"
end
else
# Development: Open access
mount MissionControl::Jobs::Engine, at: "/jobs"
end
end
Team Access Management
Granting Admin Access
# Rails console (production)
rails console
# Grant admin access to user
user = User.find_by(email: "teammate@company.com")
user.update!(admin: true)
# Or using role enum
user.update!(role: :admin)
Bulk Admin Creation
# db/seeds.rb or migration
admin_emails = [
"ops_lead@company.com",
"dev_lead@company.com",
"support_manager@company.com"
]
admin_emails.each do |email|
user = User.find_or_create_by(email: email)
user.update!(admin: true)
end
Team Roles Pattern
# app/models/user.rb
class User < ApplicationRecord
enum role: {
user: 0,
developer: 1,
operations: 2,
admin: 3
}
def can_access_jobs_dashboard?
developer? || operations? || admin?
end
end
# config/routes.rb
authenticate :user, ->(user) { user.can_access_jobs_dashboard? } do
mount MissionControl::Jobs::Engine, at: "/jobs"
end
Dashboard Features & Usage
Jobs Overview Tab
Features:
- View all jobs across all queues
- Filter by status: pending, running, finished, failed
- Real-time updates (auto-refresh)
- Queue performance metrics
Common Operations:
- Search jobs by class name
- Filter by date range
- Sort by created/finished time
Queues Tab
Metrics Displayed:
- Pending job count per queue
- Active workers per queue
- Throughput (jobs/minute)
- Latency (average wait time)
Use Cases:
- Identify bottlenecked queues
- Verify queue priority configuration
- Monitor worker capacity
Failed Jobs Tab
Features:
- Full error backtraces
- Job arguments and context
- Retry history and attempt counts
- Bulk retry/discard operations
Workflows:
-
Investigating Failures:
- Click failed job to see full backtrace
- Review job arguments for invalid data
- Check retry history for transient vs persistent failures
-
Bulk Recovery:
- Select multiple failed jobs
- Click "Retry Selected" to requeue
- Or "Discard Selected" for jobs that can't be fixed
-
Pattern Detection:
- Group by error type to find systemic issues
- Filter by time range to correlate with deployments
- Search by class name to find job-specific problems
Individual Job Details
Information Displayed:
- Job class and queue name
- Enqueued/started/finished timestamps
- Duration and execution time
- Full arguments (with sensitive params filtered)
- Error message and backtrace (if failed)
- Retry count and next retry time
Available Actions:
- Retry job (failed jobs only)
- Discard job (remove from queue)
- View full execution context
Configuration Options
Job Retention
Control how long finished and failed jobs are kept in the database:
# config/initializers/mission_control.rb
MissionControl::Jobs.configure do |config|
# Keep finished jobs for 2 weeks (default: 7 days)
config.finished_jobs_retention_period = 14.days
# Keep failed jobs for 3 months (default: 30 days)
config.failed_jobs_retention_period = 90.days
end
Automatic Cleanup:
SolidQueue automatically cleans up old jobs based on these settings. No manual intervention needed.
Manual Cleanup:
# Rails console
SolidQueue::Job.finished.where("finished_at < ?", 14.days.ago).delete_all
SolidQueue::Job.failed.where("failed_at < ?", 90.days.ago).delete_all
Parameter Filtering
Prevent sensitive data from appearing in the dashboard:
MissionControl::Jobs.configure do |config|
# Filter these parameter keys from display
config.filter_parameters = [
:password,
:token,
:secret,
:api_key,
:private_key,
:access_token,
:refresh_token,
:credit_card,
:ssn
]
end
Example Job Arguments:
# Job enqueued with:
SendEmailJob.perform_later(
user_id: 123,
password: "secret123",
api_token: "sk_live_abc123"
)
# Displayed in Mission Control as:
{
user_id: 123,
password: "[FILTERED]",
api_token: "[FILTERED]"
}
Custom Routes
Mount at a different path:
# config/routes.rb
mount MissionControl::Jobs::Engine, at: "/admin/background-jobs"
Access at: https://yourapp.com/admin/background-jobs
Production Deployment Checklist
mission_control-jobsgem added to Gemfile- Bundle installed and Gemfile.lock committed
- Routes configured with authentication
- Authentication tested in staging environment
- Admin users granted access
- Parameter filtering configured for sensitive data
- Job retention periods configured
- Team members notified of dashboard URL
- Dashboard access verified in production
- Monitoring alerts configured (optional)
Monitoring & Alerting Integration
Health Check Endpoint
Expose job queue health for external monitoring:
# app/controllers/health_controller.rb
class HealthController < ApplicationController
skip_before_action :authenticate_user! # Public endpoint
def jobs
pending_count = SolidQueue::Job.pending.count
failed_count = SolidQueue::Job.failed.count
oldest_pending = oldest_pending_job_age
status = if oldest_pending > 30 || failed_count > 100
:service_unavailable
else
:ok
end
render json: {
status: status == :ok ? "healthy" : "degraded",
pending_jobs: pending_count,
failed_jobs: failed_count,
oldest_pending_minutes: oldest_pending
}, status: status
end
private
def oldest_pending_job_age
oldest = SolidQueue::Job.pending.order(:created_at).first
return 0 unless oldest
((Time.current - oldest.created_at) / 60).round
end
end
# config/routes.rb
get '/health/jobs', to: 'health#jobs'
External Monitoring Setup
# Uptime monitoring (Pingdom, UptimeRobot, etc.)
GET https://yourapp.com/health/jobs
# Expected response (healthy):
{
"status": "healthy",
"pending_jobs": 42,
"failed_jobs": 3,
"oldest_pending_minutes": 2
}
# Alert on:
# - status != "healthy"
# - failed_jobs > threshold
# - oldest_pending_minutes > 30
Common Operations
Retry All Failed Jobs
# Rails console
SolidQueue::Job.failed.find_each(&:retry!)
# Or with Mission Control UI:
# 1. Navigate to Failed Jobs tab
# 2. Select all jobs
# 3. Click "Retry Selected"
Discard Specific Failed Jobs
# Rails console - discard jobs older than 1 week
SolidQueue::Job.failed
.where("failed_at < ?", 1.week.ago)
.delete_all
# Or by job class
SolidQueue::Job.failed
.where(class_name: "ProblematicJob")
.delete_all
Pause/Resume Queue Processing
# Not directly supported by SolidQueue
# Instead, scale workers to 0 in queue.yml and restart
# config/queue.yml (temporary)
production:
workers:
- queues: [critical, mailers]
threads: 5
processes: 0 # Paused
Monitor Specific Queue
# Rails console
SolidQueue::Job.where(queue_name: "mailers").pending.count
SolidQueue::Job.where(queue_name: "mailers").failed.count
Troubleshooting
Dashboard Not Loading
Symptom: 404 or routing error
Solutions:
- Verify gem is installed:
bundle list | grep mission_control - Check routes:
rails routes | grep jobs - Restart server after adding gem
- Check authentication constraints aren't blocking access
Authentication Loop/Redirect
Symptom: Redirected to login repeatedly
Solutions:
- Verify user is logged in:
current_userin console - Check authentication lambda:
user.admin?returns true - Verify Devise configuration allows access to mounted engines
- Check for conflicting before_action filters
Slow Dashboard Performance
Symptom: Dashboard takes >5s to load
Solutions:
- Clean up old finished jobs:
SolidQueue::Job.finished.where("finished_at < ?", 7.days.ago).delete_all - Add database indexes (if not present):
add_index :solid_queue_jobs, [:queue_name, :status] add_index :solid_queue_jobs, [:status, :created_at] - Reduce retention periods in initializer
Jobs Not Appearing
Symptom: Dashboard shows 0 jobs but jobs are running
Solutions:
- Verify SolidQueue is configured:
Rails.configuration.active_job.queue_adapter - Check queue database connection in
config/database.yml - Run queue migrations:
rails db:migrate:queue - Verify jobs are using SolidQueue, not inline adapter
Security Considerations
Production Hardening
-
Always require authentication:
# ❌ NEVER do this in production mount MissionControl::Jobs::Engine, at: "/jobs" # ✅ Always authenticate authenticate :user, ->(user) { user.admin? } do mount MissionControl::Jobs::Engine, at: "/jobs" end -
Filter sensitive parameters:
config.filter_parameters = [:password, :token, :secret, :api_key] -
Use HTTPS only:
# config/environments/production.rb config.force_ssl = true -
Limit admin access:
- Grant admin rights only to operations team
- Audit admin user list regularly
- Use role-based access for granular control
-
Monitor access logs:
# Track who accesses Mission Control class ApplicationController < ActionController::Base before_action :log_mission_control_access, if: :mission_control_request? private def mission_control_request? request.path.start_with?('/jobs') end def log_mission_control_access Rails.logger.info( "Mission Control accessed by #{current_user&.email} " \ "from #{request.remote_ip}" ) end end