The framework layer above the backend
The mid-level course "Solid Queue: job architecture", earlier in this series, looked at the tables where a job's state is stored and claimed. Every one of those tables belongs to Solid Queue, one backend. This app's jobs are never written against Solid Queue directly. They're written against ActiveJob::Base, a framework layer that sits above whichever backend runs underneath.
A job from this app, in full
app/jobs/ holds several job classes. The partner integration alone has four: fetching a partner's site icon, announcing a certificate, delivering a webhook, and pruning expired handoff nonces. Here's the smallest of them, whole:
module Partners
class FetchSiteIconJob < ApplicationJob
queue_as :default
def perform(partner_id)
partner = ::Partners::Partner.find_by(id: partner_id)
::Partners::FetchSiteIconService.call(partner: partner) if partner && !partner.logo.attached?
end
end
end
ApplicationJob inherits from ActiveJob::Base, and neither class mentions Solid Queue, its tables or FOR UPDATE SKIP LOCKED. queue_as and perform are ActiveJob vocabulary, and they work the same whether the backend is Solid Queue, Sidekiq or an in-process thread pool.
The same call, different behaviour per environment
The app sets queue_adapter per environment in config/environments/*.rb:
# development.rb
config.active_job.queue_adapter = :async
# test.rb / production.rb
config.active_job.queue_adapter = :solid_queue
::Partners::FetchSiteIconJob.perform_later(partner.id), called from Admin::Partners::SavePartnerService when a partner has no logo yet, is one line of code. In development, :async runs it on an in-process thread pool: no table, no persistence, and a server restart loses anything still queued. In test and production, :solid_queue writes a durable row to solid_queue_jobs, and a worker claims it later. Same call, same job class, two different mechanisms, decided by the environment and not by anything in FetchSiteIconJob.
What this course is about
Each lesson ahead looks at one thing ActiveJob::Base provides: argument serialisation, retry_on and discard_on, limits_concurrency, queue_as, and callbacks. It checks each one against this app's jobs, its configuration, and the Solid Queue tables underneath. It doesn't repeat the internals from "Solid Queue: job architecture"; this is the layer above them.
Key takeaways
FetchSiteIconJobis written entirely inActiveJobvocabulary; nothing in it names Solid Queue, its tables or how it claims work.- The app sets
queue_adapterper environment::asyncin development,:solid_queuein test and production. - The same
perform_latercall runs on an in-process thread pool with no persistence in development, and on Solid Queue's durable tables in test and production. - This course covers the framework layer
ActiveJob::Baseprovides above any one backend, building on "Solid Queue: job architecture" without repeating it.
Keep going with lesson 2
Arguments across the wire: GlobalID vs. a plain ID
Compares GlobalID arguments, which raise on deleted records, with plain ids and find_by, which return nil.
A free account also gives you the quizzes, your progress and notes, and the discussion.