SolidQueue gives developers a high degree of control over how and when jobs are processed, making it suitable for sophisticated workload management without needing to reach for third-party infrastructure like Redis or Kubernetes autoscalers.

This control is possible because of SolidQueue’s reliance on the database and its tight integration with Rails’ ActiveJob API.

By default, jobs are processed in the order they are enqueued (FIFO), but SolidQueue enhances this with configurable priorities, queue ordering, pausing mechanisms, and concurrency tuning.

Understanding how to properly configure and manage your queues and job priorities is essential for building responsive, efficient background systems.

Whether you want high-priority jobs like user notifications to execute before long-running tasks like data exports, or need to temporarily pause a queue during deployments, SolidQueue provides powerful yet simple-to-use APIs to make that possible. Let’s explore how.


But before we move forward with complex concepts let's iterate over what is a queue, what is a queue priority, etc.

1. What is a Queue, and Why Do Jobs Need One?

A queue in SolidQueue is just a way to group jobs. When you add a job, it goes into a named queue. This helps keep different types of work organized.

By default, jobs go into a queue named default. But you can create your own queues and name them anything — like emails, exports, or notifications. This way, you can run some jobs separately or give more power (workers) to queues that need faster processing.

Example:

class SendNewsletterJob < ApplicationJob
  queue_as :emails

  def perform(user_id)
    # code to send newsletter
  end
end

With the queue_as macro, you're explicitly categorizing your job. Workers can then be configured to only process specific queues, allowing for workload separation (e.g., notifications, low_priority, critical_tasks, etc.).


2. What is Job Priority?

Let’s say five jobs are waiting in the same queue. How do you decide which one should go first? That’s what job priority does.

In SolidQueue, a lower number means a higher priority. So, a** job with priority 1 will run before a job with priority 10**, even if it was added later.

This is very helpful when you want important jobs (like sending a password reset email) to run ahead of less urgent ones (like cleaning up old logs).

Example:

SendNewsletterJob.set(priority: 1).perform_later(user.id)

You can use any number you want — the smaller it is, the sooner the job will run.

This is particularly useful when you have thousands of jobs piling up and want certain tasks to cut ahead in the line.

If you don’t give any job a priority, SolidQueue will just run jobs in the order they were added (FIFO: First-In, First-Out). So, the job that was enqueued first will be run first — unless you’ve paused the queue or set a concurrency limit (we’ll talk about that soon). This default behavior works fine for simple use cases.


3. Pausing and Resuming Queues

Sometimes, you want to temporarily pause a queue. Maybe you are fixing a bug or your email service is down, and you don’t want the job to keep trying and failing.

In that case, you can pause a queue like this:

SolidQueue::Queue.pause("emails")

This will stop workers from picking up jobs in the emails queue.

And when you're ready to start processing again:

SolidQueue::Queue.resume("emails")

To pause and resume queues it would generally be better to create custom rake tasks which then can be used during CI/CD, as such:

a) Simple rake task

#lib/tasks/solid_queue.rake
namespace :solid_queue do
  desc "Pause emails queue"
  task pause_emails: :environment do
    SolidQueue::Queue.pause("emails")
    puts "Paused 'emails' queue"
  end
end

Then run it like this:

a) On rails console

RAILS_ENV=production bin/rake solid_queue:pause_emails

b) Advance rake task

#lib/tasks/solid_queue_control.rake
namespace :solid_queue do
  desc "Pause a specific queue"
  task :pause, [:queue_name] => :environment do |t, args|
    queue = args[:queue_name]
    if queue
      SolidQueue::Queue.pause(queue)
      puts "Paused SolidQueue '#{queue}' queue"
    else
      puts "No queue name provided!"
      exit(1)
    end
  end

  desc "Resume a specific queue"
  task :resume, [:queue_name] => :environment do |t, args|
    queue = args[:queue_name]
    if queue
      SolidQueue::Queue.resume(queue)
      puts "Resumed SolidQueue '#{queue}' queue"
    else
      puts "No queue name provided!"
      exit(1)
    end
  end
end

Then run it like this inside your docker.yml:

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Pause SolidQueue Email Queue (Pre-Migration)
        run: |
          bundle exec rake solid_queue:pause[email]
        env:
          RAILS_ENV: production
          DATABASE_URL: ${{ secrets.DATABASE_URL }}

4. Limiting How Many Jobs Run at Once (Concurrency)

Let’s say one of your jobs takes a lot of memory or connects to an external service that’s slow. You don’t want too many of these running at once— it can overload your app or bring external services to their knees.

SolidQueue lets you limit the number of jobs that run at the same time per worker using the --concurrency flag. You can do this when starting the worker process manually:

bin/rails solid_queue:work --concurrency=5 --queues=emails

This command tells the worker: “Only pick up 5 jobs from the emails queue at a time.”

You can start different workers for different queues, like so:

bin/rails solid_queue:work --concurrency=3 --queues=critical
bin/rails solid_queue:work --concurrency=2 --queues=low_priority

This gives you fine-grained control over how much parallel job load you're running across different types of work.

How to use concurrency in development environment?

In development, SolidQueue works inline by default. That means it executes jobs immediately in the same thread as your Rails app — no separate worker or polling loop needed.

So, when you do something like:

MyJob.perform_later(args)

…it actually just runs synchronously (like perform_now) behind the scenes when you're using rails server.

There’s no concurrency setting available in this inline mode — because it’s effectively single-threaded execution handled directly by Rails.

If you want to simulate concurrent job execution even in development (for testing), you can still manually run a worker process:

bin/rails solid_queue:work --concurrency=5

This will behave exactly like in production, polling jobs from the database instead of executing them inline.


5. Inspecting Queues and Priorities in Code

You can programmatically inspect queue statuses and job counts:

SolidQueue::Queue.all.each do |queue|
  puts "#{queue.name} - paused: #{queue.paused?} - pending jobs: #{queue.jobs.pending.count}"
end

This can be especially useful for building custom dashboards or integrating queue metrics into your monitoring stack.


By organizing jobs into logical queues, assigning priorities, and leveraging pausing and concurrency features, you can build a highly responsive background job processing layer that handles workloads gracefully and predictably—all without leaving Rails or reaching for additional infrastructure.