What Actually Happens When You Call perform_later
A step-by-step explanation of how Rails Active Job constructs work, hands it to a queue adapter, and why an enqueued job can sit ready without any worker ever running perform.

A step-by-step explanation of how Rails Active Job constructs work, hands it to a queue adapter, and why an enqueued job can sit ready without any worker ever running perform.

perform_later builds a job object, assigns identity and arguments, then hands a serialized description to a queue adapter — it does not move the current stack or local state to a worker process.
The adapter and backend define durability and execution semantics: different adapters (async, Solid Queue, cloud providers) store and schedule work differently, so an enqueued job may remain ready without being executed.
# What actually happens when you call perform_later
This explains the concrete lifecycle of an Active Job enqueued with perform_later, why an enqueued job might never run, and what pieces determine whether work reaches a worker.
perform_now is different: it executes perform in the current process. perform_later prepares a description of work and passes it to an adapter for handoff.
Different adapters provide different guarantees. The async adapter keeps work in process memory, so a restart loses those jobs. Solid Queue persists database rows. Both implement the same Active Job API, but they produce different durability and scheduling semantics.
Solid Queue example: it sets scheduled_at to now when preparing a stored job, stores the serialized payload in a solid_queue_jobs record, and prepares an execution record according to its scheduling and concurrency rules. Ready executions become visible to workers that match the queue configuration. When a worker claims a ready execution, Solid Queue merges the database job ID back into the serialized payload as provider_job_id before handing it to Active Job.
Those implementation details explain why a dashboard may show a job in a ready state while an error tracker has no entries, the retry count is zero, and the job never ran: the job has been accepted and stored by the backend, but no worker matching that queue claimed or executed the ready execution.
Confirm which adapter is in use, check backend storage for a provider_job_id or execution record, verify worker queue configurations, and inspect whether enqueue callbacks or adapter errors raised during handoff. Those checks identify whether the problem is enqueue-time (adapter handoff) or runtime (no worker claimed execution).
A source-backed trace of how perform_later constructs an Active Job, hands it to a queue adapter, stores backend work, and reaches a worker. It also shows why an enqueued job may never begin.

Originally appeared on Rails Revelry . The webhook receiver gets two subscription.past_due events and no subscription.active event. The application did enqueue both transitions. The first job followed trailing → active ; the second followed active → past_due . They have different Active Job IDs, both ran once, and neit

Originally appeared on Rails Revelry . What happens to the jobs already in the queue when I rename their class? The code change looks straightforward: rename the file, update the callers, and fix the tests. But a job enqueued before the deploy might wait hours or days before a worker picks it up. By then, the old class
A source-backed explanation of how Active Job turns an Active Record argument into a GlobalID locator, why workers load later row state, and how to preserve event-time facts without discarding transient deserialization failures.
Originally appeared on Island94.org . One of the small joys of computer programming is reading some code and thinking aha, that’s nice . I recently encountered this feeling of aha while reading the docs for the playwright-ruby-client ’s set up code for Capybara which described a mismatch between the Playwright and RSpe
Open the app view to save this story, compare related coverage, and continue from the same source.