Skip to content

Commit

Permalink
[RF DOCS] Add documentation for perform_all_later to Active Job Bas…
Browse files Browse the repository at this point in the history
…ics guide [ci-skip] (rails#51004)

Add documentation related to perform_all_later for bulk enqueuing jobs.

Co-authored-by: Carlos Antonio da Silva <carlosantoniodasilva@gmail.com>
  • Loading branch information
bhumi1102 and carlosantoniodasilva committed Feb 19, 2024
1 parent 5cc11f7 commit 554e71a
Showing 1 changed file with 103 additions and 2 deletions.
105 changes: 103 additions & 2 deletions guides/source/active_job_basics.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ runs jobs with an in-process thread pool. Jobs will run asynchronously, but any
jobs in the queue will be dropped upon restart.


Creating a Job
--------------
Create and Enqueue Jobs
-----------------------

This section will provide a step-by-step guide to creating a job and enqueuing it.

Expand Down Expand Up @@ -127,6 +127,10 @@ That's it!
[`perform_later`]: https://api.rubyonrails.org/classes/ActiveJob/Enqueuing/ClassMethods.html#method-i-perform_later
[`set`]: https://api.rubyonrails.org/classes/ActiveJob/Core/ClassMethods.html#method-i-set

### Enqueue Jobs in Bulk

You can enqueue multiple jobs at once using [`perform_all_later`](https://api.rubyonrails.org/classes/ActiveJob.html#method-c-perform_all_later). For more details see [Bulk Enqueuing](#bulk-enqueuing).

Job Execution
-------------

Expand Down Expand Up @@ -406,6 +410,103 @@ end
[`around_perform`]: https://api.rubyonrails.org/classes/ActiveJob/Callbacks/ClassMethods.html#method-i-around_perform
[`after_perform`]: https://api.rubyonrails.org/classes/ActiveJob/Callbacks/ClassMethods.html#method-i-after_perform

Please note that when enqueuing jobs in bulk using `perform_all_later`,
callbacks such as `around_enqueue` will not be triggered on the individual jobs.
See [Bulk Enqueuing Callbacks](#bulk-enqueue-callbacks).

Bulk Enqueuing
--------------

You can enqueue multiple jobs at once using
[`perform_all_later`](https://api.rubyonrails.org/classes/ActiveJob.html#method-c-perform_all_later).
Bulk enqueuing reduces the number of round trips to the queue data store (like
Redis or a database), making it a more performant operation than enqueuing the
same jobs individually.

`perform_all_later` is a top-level API on Active Job. It accepts instantiated
jobs as arguments (note that this is different from `perform_later`).
`perform_all_later` does call `perform` under the hood. The arguments passed to
`new` will be passed on to `perform` when it's eventually called.

Here is an example calling `perform_all_later` with `GuestCleanupJob` instances:

```ruby
# Create jobs to pass to `perform_all_later`.
# The arguments to `new` are passed on to `perform`
guest_cleanup_jobs = Guest.all.map { |guest| GuestsCleanupJob.new(guest) }

# Will enqueue a separate job for each instance of `GuestCleanupJob`
ActiveJob.perform_all_later(guest_cleanup_jobs)

# Can also use `set` method to configure options before bulk enqueuing jobs.
guest_cleanup_jobs = Guest.all.map { |guest| GuestsCleanupJob.new(guest).set(wait: 1.day) }

ActiveJob.perform_all_later(guest_cleanup_jobs)
```

`perform_all_later` logs the number of jobs successfully enqueued, for example
if `Guest.all.map` above resulted in 3 `guest_cleanup_jobs`, it would log
`Enqueued 3 jobs to Async (3 GuestsCleanupJob)` (assuming all were enqueued).

The return value of `perform_all_later` is `nil`. Note that this is different
from `perform_later`, which returns the instance of the queued job class.

### Enqueue Multiple Active Job Classes

With `perform_all_later`, it's also possible to enqueue different Active Job
class instances in the same call. For example:

```ruby
class ExportDataJob < ApplicationJob
def perform(*args)
# Export data
end
end

class NotifyGuestsJob < ApplicationJob
def perform(*guests)
# Email guests
end
end

# Instantiate job instances
cleanup_job = GuestsCleanupJob.new(guest)
export_job = ExportDataJob.new(data)
notify_job = NotifyGuestsJob.new(guest)

# Enqueues job instances from multiple classes at once
ActiveJob.perform_all_later(cleanup_job, export_job, notify_job)
```

### Bulk Enqueue Callbacks

When enqueuing jobs in bulk using `perform_all_later`, callbacks such as
`around_enqueue` will not be triggered on the individual jobs. This behavior is
in line with other Active Record bulk methods. Since callbacks run on individual
jobs, they can't take advantage of the bulk nature of this method.

However, the `perform_all_later` method does fire an
[`enqueue_all.active_job`](active_support_instrumentation.html#enqueue-all-active-job)
event which you can subscribe to using `ActiveSupport::Notifications`.

The method
[`successfully_enqueued?`](https://api.rubyonrails.org/classes/ActiveJob/Core.html#method-i-successfully_enqueued-3F)
can be used to find out if a given job was successfully enqueued.

### Queue Backend Support

For `perform_all_later`, bulk enqueuing needs to be backed by the [queue
backend](#backends).

For example, Sidekiq has a `push_bulk` method, which can push a large number of
jobs to Redis and prevent the round trip network latency. GoodJob also supports
bulk enqueuing with the `GoodJob::Bulk.enqueue` method. The new queue backend
[`Solid Queue`](https://github.com/basecamp/solid_queue/pull/93) has added
support for bulk enqueuing as well.

If the queue backend does *not* support bulk enqueuing, `perform_all_later` will
enqueue jobs one by one.

Action Mailer
------------

Expand Down

0 comments on commit 554e71a

Please sign in to comment.