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:
- Job status (finished_at, attempts)
- Errors and stack traces
- Queue lengths and priorities
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
- Use a dedicated DB user with restricted permissions for worker processes.
- Regularly prune finished jobs to avoid DB bloat.
- Monitor DB connection pool usage (each worker will use a connection).
- *Tune queue polling interval for performance *(
--poll-interval=2
).
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.