Short reference on how to quickly debug the vanilla Rails job adapters.
Queue Adapters by Environment
| Environment | Adapter | Jobs Run In | Worker Needed? |
|---|---|---|---|
| development | :async |
Rails server process | No |
| test | :test |
Not executed (stored) | No |
| production | :solid_queue |
Separate worker | Yes (bin/jobs) |
Development (:async)
Jobs run in background threads ( Concurrent Ruby ThreadPoolExecutor Show archive.org snapshot ) within the process that called the job.
- Jobs execute immediately in a background thread within
bin/rails sand write to the server logs. -
bin/jobsdoes nothing in development, jobs already run in-process via:async. - Scripts and rake tasks log go to
log/development.log
Watch out for this within the Rails or development logs:
Enqueued HelloJob (Job ID: xxx) to Async(asap)
Performing HelloJob (Job ID: xxx)
Performed HelloJob (Job ID: xxx) in 3.5s
For quick debugging, add logging or run synchronously to add a debugger:
# Skip queue, run immediately in current thread
HelloJob.perform_now(membership)
class HelloJob
def perform
puts "Hello" # → stdout of calling process (server or script terminal)
Rails.logger.info "Hello" # → log/development.log (always)
debbuger # → Work only when called within `perform_now`
end
end
Use tail -f log/development.log or tail -f log/development.log | grep -i Hello
perform_later vs perform_now
| Method | Thread |
debugger works? |
|---|---|---|
perform_later |
Background | ❌ No, hangs waiting for input. |
perform_now |
Main (blocking) | ✅ Yes |
Within perform_later the debugger will just shut down once your main process is killed or finished. Until then it will hang there waiting for input and is blocking the job.
Production (:solid_queue)
- Jobs persist to
solid_queue_*tables. - Requires
bin/jobsworker running. - You can also check
/log/production.log.
# Check pending jobs
SolidQueue::ReadyExecution.count
# Check failed jobs
SolidQueue::FailedExecution.last&.error
# Find specific job
SolidQueue::Job.where(class_name: 'HelloJob').last
Test (:test)
Jobs are not executed and only stored for assertions.
- Spawning a debugger will work independent from using
perform_noworperform_later. - For system tests you can check
/log/test.log.
assert_enqueued_with(job: HelloJob, args: [membership])
# Or execute all queued jobs
perform_enqueued_jobs do
HelloJob.perform_later('matthew')
assert_performed_jobs 1
end
Further Reading
-
Concurrent Ruby ThreadPoolExecutor
Show archive.org snapshot
: The thread pool backing
:async - Rails AsyncAdapter source Show archive.org snapshot : How Rails wraps Concurrent Ruby
- Solid Queue Show archive.org snapshot : The production queue backend
Posted by Felix Eschey to makandra dev (2025-12-04 15:54)