solid-queue-setup

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Solid Queue Setup for Rails 8

Rails 8 的 Solid Queue 配置指南

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
Solid Queue 是 Rails 8 默认的 Active Job 后端:
  • 基于数据库(无需 Redis)
  • 内置并发控制
  • 支持优先级与多队列
  • 关键任务处理能力
  • 可通过 Mission Control 使用 Web 界面

Quick Start

快速开始

Installation

安装

bash
undefined
bash
undefined

Add to Gemfile (included in Rails 8 by default)

Add to Gemfile (included in Rails 8 by default)

bundle add solid_queue
bundle add solid_queue

Install Solid Queue

Install Solid Queue

bin/rails solid_queue:install
bin/rails solid_queue:install

Run migrations

Run migrations

bin/rails db:migrate
undefined
bin/rails db:migrate
undefined

Configuration

配置

yaml
undefined
yaml
undefined

config/solid_queue.yml

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
undefined
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
undefined

Set as Active Job Adapter

设置为 Active Job 适配器

ruby
undefined
ruby
undefined

config/application.rb

config/application.rb

config.active_job.queue_adapter = :solid_queue
config.active_job.queue_adapter = :solid_queue

Or per environment

Or per environment

config/environments/production.rb

config/environments/production.rb

config.active_job.queue_adapter = :solid_queue
undefined
config.active_job.queue_adapter = :solid_queue
undefined

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)
Solid Queue 配置:
- [ ] 添加 solid_queue gem
- [ ] 执行 solid_queue:install
- [ ] 运行数据库迁移
- [ ] 在 solid_queue.yml 中配置队列
- [ ] 在配置文件中设置队列适配器
- [ ] 创建首个带测试的任务
- [ ] 测试任务执行
- [ ] 配置周期性任务(如有需要)

Creating Jobs

创建任务

Basic Job

基础任务

ruby
undefined
ruby
undefined

app/jobs/send_welcome_email_job.rb

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
undefined
class SendWelcomeEmailJob < ApplicationJob queue_as :default
def perform(user_id) user = User.find(user_id) UserMailer.welcome(user).deliver_now end end
undefined

Job with Retries

带重试机制的任务

ruby
undefined
ruby
undefined

app/jobs/process_payment_job.rb

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
undefined
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
undefined

Job with Priority

带优先级的任务

ruby
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
ruby
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

Enqueueing Jobs

任务入队

ruby
undefined
ruby
undefined

Enqueue immediately

Enqueue immediately

SendWelcomeEmailJob.perform_later(user.id)
SendWelcomeEmailJob.perform_later(user.id)

Enqueue with delay

Enqueue with delay

SendReminderJob.set(wait: 1.hour).perform_later(user.id)
SendReminderJob.set(wait: 1.hour).perform_later(user.id)

Enqueue at specific time

Enqueue at specific time

SendReportJob.set(wait_until: Date.tomorrow.noon).perform_later
SendReportJob.set(wait_until: Date.tomorrow.noon).perform_later

Enqueue on specific queue

Enqueue on specific queue

ProcessJob.set(queue: :low).perform_later(data)
ProcessJob.set(queue: :low).perform_later(data)

Perform immediately (skips queue - use sparingly)

Perform immediately (skips queue - use sparingly)

SendWelcomeEmailJob.perform_now(user.id)
undefined
SendWelcomeEmailJob.perform_now(user.id)
undefined

Recurring Jobs

周期性任务

yaml
undefined
yaml
undefined

config/recurring.yml

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
undefined
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
undefined

Testing Jobs

任务测试

Job Spec Template

任务测试用例模板

ruby
undefined
ruby
undefined

spec/jobs/send_welcome_email_job_spec.rb

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
undefined
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
undefined

Test Helpers

测试辅助工具

ruby
undefined
ruby
undefined

spec/rails_helper.rb

spec/rails_helper.rb

RSpec.configure do |config| config.include ActiveJob::TestHelper end
RSpec.configure do |config| config.include ActiveJob::TestHelper end

In specs

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
undefined
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
undefined

Running Solid Queue

运行 Solid Queue

bash
undefined
bash
undefined

Development (runs in separate terminal)

Development (runs in separate terminal)

bin/rails solid_queue:start
bin/rails solid_queue:start

Production (via Procfile)

Production (via Procfile)

Procfile

Procfile

web: bin/rails server worker: bin/rails solid_queue:start
undefined
web: bin/rails server worker: bin/rails solid_queue:start
undefined

Monitoring

监控

Mission Control (Web UI)

Mission Control(Web 界面)

ruby
undefined
ruby
undefined

Gemfile

Gemfile

gem "mission_control-jobs"
gem "mission_control-jobs"

config/routes.rb

config/routes.rb

mount MissionControl::Jobs::Engine, at: "/jobs"
undefined
mount MissionControl::Jobs::Engine, at: "/jobs"
undefined

Console Queries

控制台查询命令

ruby
undefined
ruby
undefined

Check pending jobs

Check pending jobs

SolidQueue::Job.where(finished_at: nil).count
SolidQueue::Job.where(finished_at: nil).count

Check failed jobs

Check failed jobs

SolidQueue::FailedExecution.count
SolidQueue::FailedExecution.count

Retry failed job

Retry failed job

SolidQueue::FailedExecution.last.retry
SolidQueue::FailedExecution.last.retry

Clear old completed jobs

Clear old completed jobs

SolidQueue::Job.where('finished_at < ?', 1.week.ago).delete_all
undefined
SolidQueue::Job.where('finished_at < ?', 1.week.ago).delete_all
undefined

Migration from Sidekiq

从 Sidekiq 迁移

SidekiqSolid 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:
SidekiqSolid 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: