# 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](/architecture/realtime/), 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](/features/email-campaigns/), classifying opens, recording clicks. - **Reconciliation** — [payment](/features/payments/) 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](/architecture/scaling/). The two-backend split then answers a second question: *does this job need to be transactional, or does it need to be fast?*