SolidQueue in the Real World – Common Patterns and Best Practices

SolidQueue, being a native Rails 8 background job system, naturally aligns with Rails conventions — but to harness its full potential in real-world applications, teams need to follow patterns that promote reliability, maintainability, and performance.

This section dives deep into best practices and recurring architectural patterns that developers can adopt when building production-ready systems with SolidQueue.

Whether you’re migrating from Sidekiq or starting from scratch, the following insights will help you use SolidQueue confidently in complex, high-throughput systems.


1. Queue Segregation for Job Prioritization

Using multiple named queues helps separate jobs based on urgency or importance. SolidQueue supports queue-specific job ordering and numeric priorities. For example:

class PaymentJob < ApplicationJob
  queue_as :critical
end

class NewsletterJob < ApplicationJob
  queue_as :low_priority
end

Start separate workers targeting specific queues:

bin/rails solid_queue:work --queues=critical
bin/rails solid_queue:work --queues=low_priority

This ensures that latency-sensitive tasks (like payments) aren’t blocked by bulk email jobs or periodic tasks.


2. Use Job Priorities Within Queues

SolidQueue supports numeric priorities within a queue:

class UrgentJob < ApplicationJob
  queue_as :default

  priority 10
end

Lower numbers represent higher priority. Jobs with priority: 0 will be picked before those with priority: 100. This feature is useful when the number of queues is kept minimal but you still want fine-grained control.


3. Retry Logic and Error Handling

SolidQueue defers retries, discards, and error reporting to Active Job. Always use rescue_from in jobs to handle recoverable errors gracefully:

class SyncWithAPIJob < ApplicationJob
  retry_on Net::OpenTimeout, wait: 10.seconds, attempts: 3
  discard_on ActiveRecord::RecordNotFound

  def perform(resource_id)
    resource = Resource.find(resource_id)
    ExternalAPI.sync(resource)
  end
end

Use retry_on for transient failures and discard_on for unrecoverable ones to avoid infinite retry loops and dead queues.


4. Scheduling and Delayed Jobs

SolidQueue supports scheduled jobs with native SQL timestamp checks.

You can schedule jobs using:

MyJob.set(wait: 10.minutes).perform_later(args)

Under the hood, SolidQueue checks scheduled_at timestamps before dequeuing jobs. This avoids reliance on Redis TTLs or cron-like side processes.


5. Concurrency Control and Throttling

SolidQueue supports concurrent workers and thread-safe job polling using FOR UPDATE SKIP LOCKED. However, you can implement concurrency limits for specific tasks using advisory locks, Redis (if allowed), or simple database flags.

Example:

class ReportGenerationJob < ApplicationJob
  def perform(user_id)
    return if User.find(user_id).report_in_progress?

    User.find(user_id).generate_report!
  end
end

You can also implement mutex strategies using a locked_at column or a PostgreSQL advisory lock.


6. Recurring Jobs

SolidQueue supports recurring jobs using the solid_queue:recurring_job generator.

bin/rails generate solid_queue:recurring_job purge_old_logs --every="1.day"

This creates a recurring job record that continuously reschedules itself after execution. Ideal for cleanup tasks, automated syncing, etc.


7. Monitoring and Dashboards

Because SolidQueue stores job state in your application’s DB, it’s easy to build a lightweight admin panel to track:

Example query to list failed jobs:

SELECT * FROM solid_queue_jobs
WHERE finished_at IS NULL AND error_class IS NOT NULL;

You can wrap this into an admin-only controller and display it using basic HTML views or tools like Administrate.


8. Testing with Inline Execution

For testing, you can use the :inline queue adapter to run jobs synchronously:

#config/environments/test.rb
config.active_job.queue_adapter = :inline

This simplifies test assertions:

expect { MyJob.perform_later(args) }.to change { SomeModel.count }.by(1)

For integration tests, use :test adapter and assert enqueued jobs:

assert_enqueued_with(job: MyJob, args: [123]) do
  MyJob.perform_later(123)
end

9. Graceful Worker Shutdown

Always trap SIGTERM and INT signals in worker environments (especially in Docker or Heroku) and use bin/rails solid_queue:work responsibly in Procfile or systemd:

web: bin/rails server
worker: bin/rails solid_queue:work

You can create a wrapper to log shutdown signals and flush logs before exit.


10. Production Tips


SolidQueue provides a powerful, flexible, and Rails-native way to run background jobs without the overhead of external dependencies like Redis.

With careful job design, queue management, and monitoring strategies, you can scale your background processing cleanly and confidently in real-world Rails 8 applications.