.claude/skills/solid-queue-setup/SKILL.md
Configures Solid Queue for background jobs in Rails 8. Use when setting up background processing, creating background jobs, configuring job queues, or migrating from Sidekiq to Solid Queue. WHEN NOT: Synchronous in-request processing, real-time WebSocket features (use Action Cable), or simple operations that don't need background execution.
npx skillsauth add ThibautBaissac/rails_ai_agents solid-queue-setupInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Solid Queue is Rails 8's default Active Job backend:
# Add to Gemfile (included in Rails 8 by default)
bundle add solid_queue
# Install Solid Queue
bin/rails solid_queue:install
# Run migrations
bin/rails db:migrate
# config/solid_queue.yml
default: &default
dispatchers:
- polling_interval: 1
batch_size: 500
workers:
- queues: "*"
threads: 3
processes: 1
polling_interval: 0.1
development:
<<: *default
production:
<<: *default
workers:
- queues: [critical, default]
threads: 5
processes: 2
- queues: [low]
threads: 2
processes: 1
# config/application.rb
config.active_job.queue_adapter = :solid_queue
# Or per environment
# config/environments/production.rb
config.active_job.queue_adapter = :solid_queue
Solid Queue Setup:
- [ ] Add solid_queue gem
- [ ] Run solid_queue:install
- [ ] Run migrations
- [ ] Configure queues in solid_queue.yml
- [ ] Set queue adapter in config
- [ ] Create first job with spec
- [ ] Test job execution
- [ ] Configure recurring jobs (if needed)
# app/jobs/send_welcome_email_job.rb
class SendWelcomeEmailJob < ApplicationJob
queue_as :default
def perform(user_id)
user = User.find(user_id)
UserMailer.welcome(user).deliver_now
end
end
# app/jobs/process_payment_job.rb
class ProcessPaymentJob < ApplicationJob
queue_as :critical
# Retry on specific errors
retry_on PaymentGatewayError, wait: :polynomially_longer, attempts: 5
# Don't retry on these
discard_on ActiveRecord::RecordNotFound
# Custom error handling
rescue_from(StandardError) do |exception|
ErrorNotifier.notify(exception)
raise # Re-raise to trigger retry
end
def perform(order_id)
order = Order.find(order_id)
PaymentService.new.charge(order)
end
end
class UrgentNotificationJob < ApplicationJob
queue_as :critical
# Lower number = higher priority
# Default is 0
def priority
-10
end
def perform(notification_id)
# Process urgent notification
end
end
# Enqueue immediately
SendWelcomeEmailJob.perform_later(user.id)
# Enqueue with delay
SendReminderJob.set(wait: 1.hour).perform_later(user.id)
# Enqueue at specific time
SendReportJob.set(wait_until: Date.tomorrow.noon).perform_later
# Enqueue on specific queue
ProcessJob.set(queue: :low).perform_later(data)
# Perform immediately (skips queue - use sparingly)
SendWelcomeEmailJob.perform_now(user.id)
# config/recurring.yml
production:
daily_report:
class: GenerateDailyReportJob
schedule: every day at 6am
queue: low
cleanup:
class: CleanupOldRecordsJob
schedule: every sunday at 2am
sync:
class: SyncExternalDataJob
schedule: every 15 minutes
# spec/jobs/send_welcome_email_job_spec.rb
require 'rails_helper'
RSpec.describe SendWelcomeEmailJob, type: :job do
let(:user) { create(:user) }
describe '#perform' do
it 'sends welcome email' do
expect {
described_class.perform_now(user.id)
}.to have_enqueued_mail(UserMailer, :welcome)
end
end
describe 'enqueueing' do
it 'enqueues the job' do
expect {
described_class.perform_later(user.id)
}.to have_enqueued_job(described_class)
.with(user.id)
.on_queue('default')
end
end
describe 'retry behavior' do
it 'retries on PaymentGatewayError' do
expect(described_class).to have_retry_on(PaymentGatewayError)
end
end
end
# spec/rails_helper.rb
RSpec.configure do |config|
config.include ActiveJob::TestHelper
end
# In specs
it 'processes all jobs' do
perform_enqueued_jobs do
UserSignupService.call(user_params)
end
expect(user.reload.welcome_email_sent?).to be true
end
it 'enqueues multiple jobs' do
expect {
BatchProcessor.process(items)
}.to have_enqueued_job(ProcessItemJob).exactly(items.count).times
end
# Development (runs in separate terminal)
bin/rails solid_queue:start
# Production (via Procfile)
# Procfile
web: bin/rails server
worker: bin/rails solid_queue:start
# Gemfile
gem "mission_control-jobs"
# config/routes.rb
mount MissionControl::Jobs::Engine, at: "/jobs"
# Check pending jobs
SolidQueue::Job.where(finished_at: nil).count
# Check failed jobs
SolidQueue::FailedExecution.count
# Retry failed job
SolidQueue::FailedExecution.last.retry
# Clear old completed jobs
SolidQueue::Job.where('finished_at < ?', 1.week.ago).delete_all
| Sidekiq | Solid Queue |
|---------|-------------|
| perform_async(args) | perform_later(args) |
| perform_in(5.minutes, args) | set(wait: 5.minutes).perform_later(args) |
| sidekiq_options queue: 'critical' | queue_as :critical |
| sidekiq_retry_in | retry_on with wait: |
development
Creates Turbo Streams, Turbo Frames, and morphing patterns for real-time UI updates. Use when adding real-time updates, partial page rendering, form submissions, or broadcasting. WHEN NOT: For Stimulus JavaScript controllers (see stimulus-patterns skill). For general view conventions (see rules/views.md).
testing
Writes Minitest tests with fixtures following 37signals conventions. Uses Minitest (not RSpec) and fixtures (not factories). Use when writing tests, adding test coverage, or creating fixtures. WHEN NOT: For RSpec or FactoryBot patterns (this project uses Minitest + fixtures exclusively). For test configuration/CI setup (see project docs).
tools
Builds focused, single-purpose Stimulus controllers for progressive enhancement. Use when adding JavaScript behavior, UI interactions, form enhancements, or building reusable client-side components. WHEN NOT: For Turbo Stream/Frame patterns (see turbo-patterns skill). For server-side view logic (see rules/views.md).
testing
Implements the state-as-records-not-booleans pattern for rich state tracking. Use when modeling state changes, replacing boolean flags with record-based state, or when user mentions state records, closures, publications, or toggling state. WHEN NOT: Technical flags like cached/processed (use booleans), concern extraction (use concern-patterns), general model work (use model-patterns).