Background Jobs
The platform runs 93 background job classes. They are how it keeps the request path thin: anything that does not have to finish before the shopper sees a response is handed to a queue.
Two queues, on purpose
The platform runs two job backends, each chosen for the work it carries:
| Backend | Store | Carries |
|---|---|---|
| Solid Queue | PostgreSQL | Transactional work — order confirmations, emails, OTPs, reconciliation |
| Sidekiq | Redis | High-volume real-time broadcasts |
Solid Queue puts jobs in the same database as the data they touch, so a job is enqueued in the same transaction as the change that triggered it — no “committed the order but lost the confirmation email” race. Sidekiq handles the firehose of real-time broadcasts, where Redis throughput matters more than transactional coupling.
What the jobs do
The 93 classes cluster into a few families:
- Notifications — order updates, wishlist price/restock alerts, flash-sale announcements, web push.
- Email campaigns — fanning out bulk sends, classifying opens, recording clicks.
- Reconciliation — payment settlement sync, refund sync, webhook follow-up.
- Scheduled maintenance — abandoned-cart and abandoned-wishlist reminders, flash-sale activation and expiry, cache warming.
- Real-time broadcasts — cart, inventory, wishlist, and rating updates pushed over Turbo Streams / ActionCable.
A testing gotcha
BroadcastCartUpdateJob bypasses the :test queue adapter, so any spec that
creates a cart item has to stub it explicitly — otherwise the job tries to run
for real inside the test. It is the kind of sharp edge that two job backends
introduce, and it is documented so it does not surprise the next person.
Observability
Job health is visible through a Mission Control — Jobs dashboard, covering both Solid Queue and Sidekiq, with queue-depth and failure metrics exported to Prometheus.
The principle
Every job exists to answer “no” to the question does this need to happen before the response? — see Scaling. The two-backend split then answers a second question: does this job need to be transactional, or does it need to be fast?