Open-Source Wikis

/

Ruby on Rails

/

Packages

/

Active Job

rails/rails

Active Job

Active contributors: rafaelfranca, byroot, dhh

Purpose

Active Job is a unified API for declaring and running background jobs across a variety of queue backends. The framework defines the job class shape (perform, before_enqueue, retry_on, etc.); pluggable adapters connect Sidekiq, Resque, Solid Queue, GoodJob, Delayed Job, and others.

Source: activejob/lib/active_job/. ~4,700 lines of lib/ Ruby.

Directory layout

activejob/
├── lib/
│   └── active_job/
│       ├── base.rb                          # ActiveJob::Base
│       ├── arguments.rb                     # Argument serialization
│       ├── callbacks.rb
│       ├── configured_job.rb                # MyJob.set(wait: 1.minute)
│       ├── continuable.rb / continuation/   # Resumable jobs
│       ├── core.rb
│       ├── enqueue_after_transaction_commit.rb
│       ├── enqueuing.rb
│       ├── exceptions.rb                    # retry_on / discard_on
│       ├── execution.rb
│       ├── instrumentation.rb
│       ├── log_subscriber.rb
│       ├── queue_adapter.rb
│       ├── queue_adapters/                  # Built-in adapters
│       ├── queue_name.rb / queue_priority.rb
│       ├── railtie.rb
│       ├── serializers/                     # Argument type serializers
│       ├── structured_event_subscriber.rb
│       ├── test_case.rb
│       └── test_helper.rb
└── activejob.gemspec

Key abstractions

Constant File Purpose
ActiveJob::Base activejob/lib/active_job/base.rb Subclass for every job
ActiveJob::Arguments activejob/lib/active_job/arguments.rb Serializes job arguments to a JSON-safe form
ActiveJob::QueueAdapters::AbstractAdapter activejob/lib/active_job/queue_adapters/abstract_adapter.rb Base class for adapters
ActiveJob::ConfiguredJob activejob/lib/active_job/configured_job.rb Result of MyJob.set(wait: 1.minute)
ActiveJob::Continuation activejob/lib/active_job/continuation/ Step-based resumable jobs

Built-in queue adapters

activejob/lib/active_job/queue_adapters/:

  • async_adapter.rb — runs jobs in a thread pool in-process (development default).
  • inline_adapter.rb — runs jobs synchronously (test default).
  • test_adapter.rb — captures jobs in arrays for assertions.
  • backburner_adapter.rb
  • delayed_job_adapter.rb
  • queue_classic_adapter.rb
  • resque_adapter.rb
  • sneakers_adapter.rb

External adapters (Sidekiq, Solid Queue, GoodJob, Mission Control) live in their own gems and register via:

class ActiveJob::QueueAdapters::SidekiqAdapter
  def enqueue(job)
    # ...
  end
end

The abstract_adapter.rb defines the contract: enqueue(job), enqueue_at(job, timestamp), and optionally enqueue_all(jobs) for batch enqueuing.

Job lifecycle

sequenceDiagram
    participant App
    participant Job as MyJob
    participant Adapter as Queue Adapter
    participant Worker
    App->>Job: MyJob.perform_later(args)
    Job->>Job: serialize arguments
    Job->>Adapter: enqueue
    Adapter-->>App: ok
    Worker->>Adapter: poll
    Adapter->>Worker: job payload
    Worker->>Job: deserialize, perform_now
    Job->>Job: callbacks → perform → callbacks

Argument serialization

ActiveJob::Arguments (activejob/lib/active_job/arguments.rb) walks job arguments and converts them to JSON-safe types:

  • Primitives (String, Integer, etc.) pass through.
  • Symbol, Date, DateTime, Time, BigDecimal, Range, etc. are serialized via custom serializers in activejob/lib/active_job/serializers/.
  • Active Record objects use GlobalID::Identification so a User is serialized as gid://app/User/123 and re-fetched on the worker side.

Custom types can be supported by subclassing ActiveJob::Serializers::ObjectSerializer.

Retries and discards

activejob/lib/active_job/exceptions.rb:

  • retry_on ExceptionClass, wait: 5.seconds, attempts: 5 — exponential backoff and policy.
  • discard_on ExceptionClass — drop without retry.
  • rescue_from — handle inside perform.

The wait: argument supports a Proc or the symbol :polynomially_longer for adaptive backoff.

enqueue_after_transaction_commit

activejob/lib/active_job/enqueue_after_transaction_commit.rb is the integration point that delays enqueue until any wrapping Active Record transaction commits. This avoids the classic race where a worker tries to load a record before the inserting transaction is visible. Configured per-job; default depends on config.active_job.enqueue_after_transaction_commit.

Continuations

activejob/lib/active_job/continuation/ is a recently-added subsystem for resumable jobs. A long-running job can checkpoint after each step and, if the worker is killed (deploy, OOM), resume from the last completed step on the next attempt:

class ImportJob < ApplicationJob
  include ActiveJob::Continuable
  def perform(import_id)
    step :extract do
      ...
    end
    step :transform do
      ...
    end
    step :load do
      ...
    end
  end
end

Implementation: continuation.rb, continuable.rb, continuation/step.rb, continuation/state.rb. The continuation state is serialized into the job arguments.

Instrumentation

Active Job publishes:

  • enqueue.active_job
  • enqueue_at.active_job
  • enqueue_retry.active_job
  • perform_start.active_job
  • perform.active_job
  • discard.active_job

Subscribers in log_subscriber.rb and structured_event_subscriber.rb translate them into log lines.

Testing

ActiveJob::TestCase (activejob/lib/active_job/test_case.rb) and ActiveJob::TestHelper (test_helper.rb) provide:

  • assert_enqueued_with(job: MyJob, args: [1, 2])
  • assert_enqueued_jobs n
  • perform_enqueued_jobs do ... end
  • assert_no_enqueued_jobs

By default tests use the :test adapter, which captures jobs in enqueued_jobs / performed_jobs arrays.

Integration points

  • Active Record: enqueue_after_transaction_commit ties enqueue to transaction commit. DestroyAssociationAsyncJob in Active Record uses Active Job for dependent: :destroy_async.
  • Action Mailer: MailDeliveryJob is an Active Job subclass.
  • Action Mailbox: RoutingJob and IncinerationJob route inbound email via Active Job.
  • Active Storage: background analyses, transcoding, and purges are Active Jobs.

Entry points for modification

  • Adding a queue adapter: subclass ActiveJob::QueueAdapters::AbstractAdapter, implement enqueue / enqueue_at. Tests under activejob/test/cases/queue_adapters/.
  • Adding an argument serializer: subclass ActiveJob::Serializers::ObjectSerializer. Register on ActiveJob::Serializers.add_serializers.
  • Adding a callback: declare via before_enqueue, around_perform etc. (ActiveJob::Callbacks).

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Active Job – Ruby on Rails wiki | Factory