| name | solid-queue-setup |
| description | 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. |
| allowed-tools | Read, Write, Edit, Bash |
Solid Queue Setup for Rails 8
Overview
Solid Queue is Rails 8's default Active Job backend:
- Database-backed (no Redis required)
- Built-in concurrency controls
- Supports priorities and multiple queues
- Mission-critical job processing
- Web UI available via Mission Control
Quick Start
Installation
bundle add solid_queue
bin/rails solid_queue:install
bin/rails db:migrate
Configuration
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
Set as Active Job Adapter
config.active_job.queue_adapter = :solid_queue
config.active_job.queue_adapter = :solid_queue
Workflow Checklist
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)
Creating Jobs
Basic Job
class SendWelcomeEmailJob < ApplicationJob
queue_as :default
def perform(user_id)
user = User.find(user_id)
UserMailer.welcome(user).deliver_now
end
end
Job with Retries
class ProcessPaymentJob < ApplicationJob
queue_as :critical
retry_on PaymentGatewayError, wait: :polynomially_longer, attempts: 5
discard_on ActiveRecord::RecordNotFound
rescue_from(StandardError) do |exception|
ErrorNotifier.notify(exception)
raise
end
def perform(order_id)
order = Order.find(order_id)
PaymentService.new.charge(order)
end
end
Job with Priority
class UrgentNotificationJob < ApplicationJob
queue_as :critical
def priority
-10
end
def perform(notification_id)
end
end
Enqueueing Jobs
SendWelcomeEmailJob.perform_later(user.id)
SendReminderJob.set(wait: 1.hour).perform_later(user.id)
SendReportJob.set(wait_until: Date.tomorrow.noon).perform_later
ProcessJob.set(queue: :low).perform_later(data)
SendWelcomeEmailJob.perform_now(user.id)
Recurring Jobs
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
Testing Jobs
Job Spec Template
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 change { ActionMailer::Base.deliveries.count }.by(1)
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
Test Helpers
RSpec.configure do |config|
config.include ActiveJob::TestHelper
end
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
Running Solid Queue
bin/rails solid_queue:start
web: bin/rails server
worker: bin/rails solid_queue:start
Monitoring
Mission Control (Web UI)
gem "mission_control-jobs"
mount MissionControl::Jobs::Engine, at: "/jobs"
Console Queries
SolidQueue::Job.where(finished_at: nil).count
SolidQueue::FailedExecution.count
SolidQueue::FailedExecution.last.retry
SolidQueue::Job.where('finished_at < ?', 1.week.ago).delete_all
Migration from Sidekiq
| 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: |
Sidekiq::Client.push_bulk(...) | ActiveJob::Base.perform_all_later(*jobs) |
sidekiq_throttle concurrency: { limit: N } | Dedicated queue with threads: N in solid_queue.yml |
Related Skills
| Need | Use |
|---|
| Dispatching N worker jobs from one scheduler job | job-fan-out-pattern skill |
| Capping concurrent workers for external API rate limits | queue-concurrency-throttling skill |
| Bulk DB operations inside a job (insert_all, upsert_all) | bulk-operations skill |
| External API calls with gateway layer and retry strategy | external-api-integration skill |