---
title: "Rails Active Jobとは？perform_laterとSolid Queue・retry_onの使い方【Rails 8.1.4】"
url: "https://www.issoh.co.jp/tech/details/3988/"
published: 2024-10-29
updated: 2026-10-28
categories: ["Ruby on Rails"]
publisher: "株式会社一創"
---

# Rails Active Jobとは？perform\_laterとSolid Queue・retry\_onの使い方【Rails 8.1.4】

Active Jobは、Ruby on Railsで重い処理をバックグラウンドのジョブとして切り出すための共通APIです。ジョブの書き方はActive Jobで統一し、実際にキューへ保存して実行するのはSolid QueueやSidekiqといったバックエンドが受け持ちます。この記事では、2026年9月24日公開のRails 8.1.4と、Rails 8から既定バックエンドになったSolid Queue 1.7.0を手元で動かし、ジョブの作成と`perform_later`での投入、`retry_on`の待ち時間、トランザクションをロールバックしてもジョブが残る落とし穴、テストの書き方までを確かめた結果で整理します。

## まとめ：Active Jobの要点（Rails 8.1.4時点）

- Active Jobはジョブを書くためのAPIで、ジョブを保存・実行するのはバックエンド。Rails 8.0以降の新規アプリは、本番環境だけが`:solid_queue`に設定され、開発環境は`:async`、テスト環境は`:test`で動く。
- ジョブは`ApplicationJob`を継承して書き、`perform_later`でキューへ積む。戻り値は受け取れないので、結果はDBや通知で扱う。
- Solid Queueでは`retry_on`を書かない限り失敗したジョブは再試行されない。実測でも例外を投げたジョブは1回で失敗扱いになった。
- `wait: :polynomially_longer`の待ち時間は「実行回数の4乗＋2秒」。既定の5回なら再試行の待ちは3秒・18秒・83秒・258秒（揺らぎ最大15％を加算）。
- Rails 8の既定構成はキュー用DBが別のため、トランザクションをロールバックしてもジョブは残って実行される。`enqueue_after_transaction_commit`を有効にするか、`after_commit`から投入する。

## Active Jobの役割と環境ごとの既定アダプタ

Webリクエストの中でメール送信や外部API連携を同期実行すると、その時間だけレスポンスが遅れます。Active Jobはこうした処理をジョブとして切り出し、後からワーカーに実行させる仕組みで、Rails 4.2で標準に入りました。

### ジョブのAPIとバックエンドの分担

Active Jobが決めるのは、ジョブクラスの書き方（`perform`）、投入の書き方（`perform_later`）、リトライやコールバックの宣言方法です。ジョブをどこに保存し、どのプロセスが実行するかはキューアダプタ（バックエンド）の仕事です。アダプタは`config.active_job.queue_adapter`で切り替えられ、Active Jobの共通APIだけを使うジョブなら、通常は本体を書き換えずに切り替えられます。ただし、Solid Queue固有の同時実行制御などは移行先での見直しが必要です。

### 何も設定しないときのアダプタ

Rails 8.1.4のrailtieは、アダプタが未設定なら`Rails.env.test? ? :test : :async`を入れます。`rails new`で作ったアプリを確認すると、`queue_adapter`を設定しているのは`config/environments/production.rb`の`:solid_queue`だけでした。つまり開発環境で`perform_later`したジョブはSolid Queueではなく`:async`で動きます。

`:async`は同期実行ではありません。Railsプロセス内のスレッドプールで非同期に実行しますが、キューはメモリ上にしか無く、サーバーを再起動すると未実行のジョブは消えます。本番で使うアダプタではない、というのが[AsyncAdapterのAPIドキュメント](https://api.rubyonrails.org/classes/ActiveJob/QueueAdapters/AsyncAdapter.html)の位置づけです。

| アダプタ          | 保存先         | 実行             | 主な用途         |
| ------------- | ----------- | -------------- | ------------ |
| :async        | メモリ         | プロセス内スレッド      | 開発環境の既定      |
| :inline       | なし          | その場で同期         | デバッグ         |
| :test         | メモリ         | 実行しない（記録のみ）    | テスト環境の既定     |
| :solid\_queue | RDB（キュー用DB） | bin/jobs のワーカー | Rails 8の本番既定 |
| :sidekiq      | Redis       | sidekiq プロセス   | 高スループット      |

## ApplicationJobによるジョブ定義とperform\_laterによる投入

### rails generate jobによる雛形の生成

ジョブはジェネレータで作ります。生成されるクラスは`ApplicationJob`を継承し、処理本体を`perform`に書きます。`ApplicationJob`はアプリ全体のジョブの親クラスで、全ジョブ共通の`retry_on`や`rescue_from`をここに書いておけます。ジェネレータの他のオプションは[Railsジェネレータ（rails generate）の使い方](/tech/details/2874/)にまとめています。

```
$ bin/rails generate job guests_cleanup
      create  app/jobs/guests_cleanup_job.rb
      create  test/jobs/guests_cleanup_job_test.rb

# app/jobs/guests_cleanup_job.rb
class GuestsCleanupJob < ApplicationJob
  queue_as :default

  def perform(guest)
    guest.destroy
  end
end
```

### perform\_later・perform\_now・set の使い分け

`perform_later`はキューへ積んだ時点で戻り、呼び出し側はジョブの完了を待ちません。`perform_now`はその場で`perform`を実行して戻り値を返します。実行時刻やキューを変えたいときは`set`を挟みます。

```
GuestsCleanupJob.perform_later(guest)                                # キューに積んで即戻る
GuestsCleanupJob.perform_now(guest)                                  # その場で実行
GuestsCleanupJob.set(wait: 1.week).perform_later(guest)              # 1週間後以降に実行
GuestsCleanupJob.set(wait_until: Date.tomorrow.noon).perform_later(guest)
GuestsCleanupJob.set(queue: :low_priority, priority: 10).perform_later(guest)
```

`wait_until`が保証するのは「その時刻より前には実行しない」ことだけです。Solid Queueの場合、予定時刻になったジョブを実行待ちへ移すディスパッチャは既定で1秒ごとにポーリングし、さらにワーカーが空いている必要があります。秒単位で時刻を守る用途には向きません。

### 引数に渡せる型とGlobalID

ジョブの引数はキューへ保存するためにシリアライズされます。文字列・数値・`nil`・真偽値・配列・ハッシュに加え、Rails 8.1.4は`Symbol`・`Date`・`Time`・`DateTime`・`ActiveSupport::TimeWithZone`・`ActiveSupport::Duration`・`BigDecimal`・`Range`、クラスやモジュールそのものを扱えます（[arguments.rb](https://github.com/rails/rails/blob/v8.1.4/activejob/lib/active%5Fjob/arguments.rb)）。Active Recordのモデルを渡すとGlobalID（`gid://app/Guest/1`のような文字列）で保存され、実行時にレコードを引き直します。

実行までにレコードが削除されていると、引き直しで`ActiveJob::DeserializationError`になります。削除済みレコードが復元されない運用なら、後述の`discard_on`で破棄できます。ただし、この例外は復元処理中の別のエラーも包むため、原因を確認して破棄対象を決めます。独自クラスを渡したいときは`ActiveJob::Serializers::ObjectSerializer`を継承したシリアライザを`config.active_job.custom_serializers`に登録します。

### perform\_all\_laterによる一括投入とコールバックの制約

大量のジョブを積むときは、Rails 7.1で入った`ActiveJob.perform_all_later`でまとめて投入できます。Solid Queueのように一括挿入に対応したアダプタでは、1件ずつ`perform_later`するより往復が減ります。

```
jobs = User.where(active: true).map { |user| WelcomeJob.new(user) }
ActiveJob.perform_all_later(jobs)
```

注意点が2つあります。手元のテストでは、`perform_all_later`の戻り値は`nil`（Active Recordを読み込んだRails 8.1.4では常に`nil`を返す実装）で、`before_enqueue`に登録したコールバックは1回も呼ばれませんでした。投入時のコールバックでログや計測をしている場合、一括投入ではそれが抜けます。また、Solid Queueの同時実行制御（`limits_concurrency`）を設定したジョブも一括投入はできますが、[solid\_queue 1.7.0のREADME](https://github.com/rails/solid%5Fqueue/blob/v1.7.0/README.md)によると制限を守るために内部で1件ずつ投入されるため、一括投入の利点はなくなります。

## Solid Queueの設定とジョブ実行（Rails 8の既定）

Solid Queueは、ジョブをRDB（PostgreSQL・MySQL・SQLite）に保存するバックエンドです。Redisは不要です。PostgreSQLやMySQL 8のように`FOR UPDATE SKIP LOCKED`に対応したDBでは、この句で複数のワーカーがロック待ちせずに別々のジョブを取り出します。SQLiteはこの句に対応していないため使われず、書き込みはDB単位のロックで順番に処理されます。ここからは、Ruby 4.0.6・Rails 8.1.4・solid\_queue 1.7.0・SQLiteで新規アプリを作り、本番環境（`RAILS_ENV=production`）でワーカーを動かした結果です。

### 生成されるファイルと bin/jobs の起動

`rails new`はGemfileに`solid_queue`を入れ、`bin/rails solid_queue:install`が次のファイルを作ります。

- `config/queue.yml`：ワーカーとディスパッチャの設定
- `config/recurring.yml`：定期実行するジョブの定義
- `db/queue_schema.rb`：キュー用DBのテーブル定義
- `bin/jobs`：ワーカーを起動するコマンド
- `production.rb`への追記：`queue_adapter = :solid_queue`と`solid_queue.connects_to = { database: { writing: :queue } }`

最後の行が重要で、Rails 8の既定構成ではジョブはアプリ本体とは別のキュー用DB（`database.yml`の`queue`）に保存されます。`bin/rails db:prepare`でキュー用DBを作り、`bin/jobs`でワーカーを起動します。Webサーバーと同じプロセスで動かしたい小規模な構成なら、`config/puma.rb`に生成済みの`plugin :solid_queue if ENV["SOLID_QUEUE_IN_PUMA"]`を使い、環境変数`SOLID_QUEUE_IN_PUMA`を設定します。ただし既定では別プロセスをforkします。同一プロセスで動かすには、さらに`solid_queue_mode :async`の指定が必要です。

```
$ export RAILS_ENV=production
$ bin/rails db:prepare     # storage/production_queue.sqlite3 などが作られる
$ bin/jobs                 # スーパーバイザがワーカーとディスパッチャを起動する
```

### queue.yml の既定値とキューの優先順位

生成された`queue.yml`は、ディスパッチャが1秒間隔・500件ずつ、ワーカーが全キュー（`"*"`）・3スレッド・1プロセス（環境変数`JOB_CONCURRENCY`で変更）です。ワーカーの`polling_interval`はテンプレートでは`1`ですが、`queue.yml`が無いときにSolid Queueが使う組み込みの既定値は`0.1`秒でした（solid\_queue 1.7.0の`configuration.rb`）。ジョブの拾いが遅いと感じたら、まずここを見ます。

```
# config/queue.yml（生成直後）
default: &default
  dispatchers:
    - polling_interval: 1
      batch_size: 500
  workers:
    - queues: "*"
      threads: 3
      processes: <%= ENV.fetch("JOB_CONCURRENCY", 1) %>
      polling_interval: 1
```

キューの優先順位は、`queues: [critical, default, low]`のように並べた順が厳密に効きます。数値の`priority`は小さい値ほど優先されます（既定0）。キューを順序付きで指定した場合はキュー順が優先されますが、`queues: "*"`ではキューをまたいで数値優先度が比較されます。上位のキューが常に詰まっていると下位のキューは実行されないので、重いバッチは別ワーカーに分けるのが安全です。

### limits\_concurrencyによる同時実行数の制限

同じ顧客に対する同期処理を並行させたくない、といった場面ではSolid Queueの`limits_concurrency`を使います。`key`が同じジョブは`to`で指定した数までしか同時に実行されず、残りはブロックされて待ちます。

```
class ConcJob < ApplicationJob
  limits_concurrency to: 1, key: ->(account_id, _n) { account_id }, duration: 1.minute

  def perform(account_id, n)
    sleep 2
  end
end

[1, 1, 1, 2].each_with_index { |a, i| ConcJob.perform_later(a, i) }
```

4件を投入した直後は、実行待ち5件（他のジョブを含む）に対してブロック中が2件でした。ワーカーのログでは、account 1の3件は順番に実行され、前のジョブ終了から次の開始までの間隔は約1.3秒と約0.4秒でした。account 2の1件はaccount 1と並行して始まりました。`to`の既定は1、`duration`の既定は3分で、`duration`はロックが解放されない場合の保険です。期限を過ぎたジョブは解除候補となり、ディスパッチャの保守処理で確認されます。保守間隔は既定600秒で、期限直後の解除は保証されません。処理時間がこの期限を十分下回る値に設定してください。上限に当たったジョブを待たせず捨てたいときは`on_conflict: :discard`を指定します（既定は`:block`）。

### recurring.ymlによる定期実行の設定

cronのような定期実行は`config/recurring.yml`に書き、ディスパッチャと同じスーパーバイザ配下のスケジューラが投入します。`schedule`は「every hour at minute 12」のような自然文を[Fugit](https://github.com/floraison/fugit)で解釈します。生成直後のファイルには、終了済みジョブを1時間ごとに消すタスクが本番用に入っています。

```
production:
  clear_solid_queue_finished_jobs:
    command: "SolidQueue::Job.clear_finished_in_batches(sleep_between_batches: 0.3)"
    schedule: every hour at minute 12
  nightly_report:
    class: NightlyReportJob
    queue: low
    schedule: at 3am every day
```

## retry\_onとdiscard\_onによる再試行・破棄の設定

### Solid Queueの再試行の既定とretry\_onの必要性

Sidekiqは独自の仕組みで失敗したジョブを既定で25回再試行しますが、Solid Queueにはその仕組みがありません。例外を投げるだけのジョブ（`retry_on`なし）を流すと、1回実行されて`solid_queue_failed_executions`に1行入り、それきりでした。再試行させたい例外は、ジョブか`ApplicationJob`に`retry_on`で明示します。

```
class RetryJob < ApplicationJob
  retry_on ArgumentError, wait: 2.seconds, attempts: 3

  def perform
    raise ArgumentError, "always"
  end
end
```

このジョブは3回実行され、間隔はそれぞれ3.9秒と3.7秒でした。待ち時間2秒に、揺らぎ（最大15％）と、ディスパッチャ・ワーカーのポーリング間隔（どちらも1秒）が上乗せされた値です。`attempts`を使い切ると例外がSolid Queueまで伝わり、ジョブは失敗済みとして残ります。失敗したジョブの一覧・再実行・破棄は、Rails公式の管理画面[Mission Control Jobs](https://github.com/rails/mission%5Fcontrol-jobs)（2026年9月公開の1.3.1）で行えます。

### :polynomially\_longer の待ち時間

`retry_on`の既定は`wait: 3.seconds`・`attempts: 5`です。`wait: :polynomially_longer`にすると、Rails 8.1.4の`determine_delay`は「実行回数の4乗＋揺らぎ＋2秒」を返します。旧名の`:exponentially_longer`は計算が指数でなかったため改名されたもので、ソースのコメントにも「以前は誤ってexponentialと呼んでいた」とあります。

揺らぎは`rand × 実行回数の4乗 × 0.15`で、待ちを最大15％延ばす方向にだけ働きます（`config.load_defaults`が6.1以上なら`retry_jitter`は0.15）。揺らぎを0にして実際に計算した値は次のとおりです。

| 失敗した実行回数 | 次の再試行までの待ち          | 累計        |
| -------- | ------------------- | --------- |
| 1回目      | 3秒                  | 3秒        |
| 2回目      | 18秒                 | 21秒       |
| 3回目      | 83秒                 | 104秒      |
| 4回目      | 258秒                | 362秒（約6分） |
| 5回目      | 再試行しない（attempts: 5） | –         |

既定の5回だと、最初の失敗から6分ほどで諦めます。外部APIの数十分の障害に耐えさせたいなら`attempts`を増やします。`attempts: 10`なら揺らぎを除いた待ちの合計は15,351秒（約4.3時間）で、増やすほど1回あたりの待ちが急に伸びる点に注意してください。成功するまで続けたい場合は`attempts: :unlimited`を指定できますが、直らない例外でキューを占有し続けるので、対象の例外を絞って使います。

```
class RemoteSyncJob < ApplicationJob
  retry_on Net::OpenTimeout, Faraday::ServerError, wait: :polynomially_longer, attempts: 10
  retry_on RateLimitedError, wait: ->(executions) { executions * 60 }   # 独自の待ち時間
  discard_on ActiveJob::DeserializationError

  def perform(record)
    ExternalApi.sync(record)
  end
end
```

Rails 8.1では`retry_on`と`discard_on`に`report: true`が追加され、再試行や破棄の前に`Rails.error`のエラーレポーターへ通知できるようになりました。

### discard\_on・after\_discard と冪等性

再試行しても結果が変わらない失敗は`discard_on`で破棄します。破棄したことを記録したい場合は、Rails 7.1で入った`after_discard`を使うと、`retry_on`の上限到達と`discard_on`のどちらで捨てられたときも呼ばれます。

```
class WelcomeJob < ApplicationJob
  discard_on ActiveJob::DeserializationError
  after_discard do |job, error|
    Rails.logger.warn("discarded #{job.class} #{job.job_id}: #{error.class}")
  end

  def perform(user)
    UserMailer.welcome(user).deliver_now
  end
end
```

再試行がある以上、同じジョブが2回実行されても結果が壊れないこと（冪等性）が前提になります。DBへの二重登録は一意制約で防げますが、メール送信と送信済みフラグの更新は一体ではありません。送信直後の障害では重複送信が起こり得るため、配信サービスの冪等性キーや重複許容方針も検討します。なお`retry_on`と`discard_on`は内部的に`rescue_from`なので、後に書いた宣言が先に照合されます。親クラスの例外を広く拾う宣言は上に、具体的な例外の宣言は下に書きます。

## トランザクションとジョブ投入のずれ

Rails 8でSolid Queueを使うときに最も気づきにくいのがここです。モデルの保存とジョブの投入を同じトランザクションに入れても、Rails 8の既定構成ではジョブはキュー用DBという別の接続に書かれるため、アプリ側のトランザクションに巻き込まれません。

```
class TxJob < ApplicationJob
  def perform(label) = Rails.logger.info("performed #{label}")
end

class TxAfterCommitJob < TxJob
  self.enqueue_after_transaction_commit = true
end

ActiveRecord::Base.transaction do
  TxJob.perform_later("default(false)")
  TxAfterCommitJob.perform_later("after_commit(true)")
  raise ActiveRecord::Rollback
end
```

このコードを実行すると、ロールバックしたにもかかわらず`TxJob`はキュー用DBに残り、ワーカーを起動すると実行されました。`enqueue_after_transaction_commit = true`を付けた`TxAfterCommitJob`はキューに積まれていません。保存に失敗した注文に確認メールが飛ぶ、削除されたはずのレコードでジョブが`DeserializationError`になる、といった不具合はこれが原因です。

この設定は版ごとに変わってきました。Rails 7.2では`:always`・`:never`・`:default`（アダプタに任せる）の3値でしたが、Rails 8.0で真偽値になり既定は`false`、アプリ全体に効かせる`config.active_job.enqueue_after_transaction_commit`も非推奨になりました（[v8.1.4のenqueuing.rb](https://github.com/rails/rails/blob/v8.1.4/activejob/lib/active%5Fjob/enqueuing.rb)）。Rails 8.1.4ではジョブクラスごとに指定します。モデルの保存に続けてジョブを投入するクラスには`ApplicationJob`などで`true`を設定するか、モデルの`after_commit`コールバックから`perform_later`します。`true`にした場合、`perform_later`はコミットまで実際の投入を遅らせ、Rails 8.1からは`before_enqueue`などのコールバックもコミット後に回ります。呼び出し直後に、ジョブがキューに入ったかどうかは判断できません。トランザクションコールバック側の変更は[ActiveRecord 7.2の変更点](/tech/details/10104/)で実行して確かめています。

## ActiveJob::TestHelperによる投入・実行のテスト

テスト環境のアダプタは`:test`で、`perform_later`しても実行せず「積まれた」記録だけを残します。そのため、テストは「正しく積まれたか」と「実行した結果どうなるか」を分けて書きます。`ActiveJob::TestCase`（またはテストクラスに`include ActiveJob::TestHelper`）で使える主なアサーションは次の3つです。

```
require "test_helper"

# この節で使う、メール送信を行わないテスト専用のジョブ定義
class WelcomeJob < ApplicationJob
  queue_as :mailers
  def perform(name) = "hello #{name}"
end

class WelcomeJobTest < ActiveJob::TestCase
  test "キュー名と引数つきで投入される" do
    assert_enqueued_with(job: WelcomeJob, args: ["taro"], queue: "mailers") do
      WelcomeJob.perform_later("taro")
    end
  end

  test "perform_enqueued_jobs のブロック内で投入したジョブは実行される" do
    perform_enqueued_jobs do
      WelcomeJob.perform_later("hanako")
    end
    assert_performed_jobs 1
    assert_enqueued_jobs 0
  end
end
```

このテストファイルをそのまま手元のRails 8.1.4アプリで実行し、2件・5アサーションとも通りました。`perform_enqueued_jobs`はブロックを渡すとブロック内で積まれたジョブを実行し、ブロック無しで呼ぶとそれまでに積まれたジョブをまとめて実行します。RSpecでは`rspec-rails`の`have_enqueued_job`マッチャを使います。

```
expect { WelcomeJob.perform_later("taro") }
  .to have_enqueued_job(WelcomeJob).with("taro").on_queue("mailers")
```

コントローラーからジョブが積まれることを確かめるなら、リクエストを投げて`have_enqueued_job`を当てるのが手早い方法です。書き方は[request specとは？Rails 8・RSpec 8でのリクエストスペックの書き方](/tech/details/3993/)を参照してください。

## Solid Queue以外のバックエンドを選ぶ条件

新規アプリはSolid Queueから始め、次のどれかに当たったら乗り換えを検討する、という順番で判断して構いません。

- **ジョブ数が多く、DBのポーリング負荷が気になる**：Redisを使う[Sidekiq](/tech/details/7843/)（最新は8.1.7）が候補です。ただしRails 8.1でActive Jobに組み込まれていた`sidekiq`アダプタは非推奨になり、Rails 8.2で削除されます。Sidekiq 7.3.3以降が同梱するアダプタを使うので、`config.active_job.queue_adapter = :sidekiq`の書き方はそのままで、Sidekiqのバージョンを上げておきます。
- **AWSでSQSにキューを任せたい**：SQSをバックエンドにする[Shoryuken](/tech/details/3429/)があります。
- **Delayed Job・Resqueを使い続けている**：どちらもActive Job経由で書いていればジョブ本体はそのまま移せます。新規に選ぶ理由は、DBで動くならSolid Queue、Redisで動くならSidekiqがある今は乏しいでしょう。

Active Job自体を使わないほうがよい場面もあります。ユーザーの操作に対して即座に結果を返す処理（決済の確定など）は、キューの遅延が入るので同期で書きます。数時間かかるジョブは、終了猶予内に完了できずワーカーが強制終了すると、Solid Queueでは失敗扱いになる場合があります。通常のジョブを再実行すると処理の先頭から始まります。Rails 8.1の`ActiveJob::Continuable`で区切りごとに再開できるようにする方法は[Active Job Continuationsとは？](/tech/details/8853/)で扱っています。

## よくある質問

### Active JobとSidekiqの違いは何ですか？

Active Jobはジョブの書き方を揃えるRailsのAPIで、Sidekiqはジョブを保存・実行するバックエンドです。Active Jobで書いたジョブを、アダプタに`:sidekiq`を指定してSidekiqで動かす、という組み合わせになります。

### 開発環境でperform\_laterしたジョブがbin/jobsを起動しなくても実行されるのはなぜですか？

`rails new`で作ったアプリは本番環境にだけ`:solid_queue`を設定しており、開発環境は既定の`:async`で動くためです。`:async`はRailsプロセス内のスレッドで実行します。開発環境でもSolid Queueを使うなら、`development.rb`にアダプタとキュー用DBの接続を書き、`bin/jobs`を起動します。

### perform\_laterした処理の戻り値は受け取れますか？

受け取れません。`perform_later`が返すのは通常ジョブのインスタンスで、処理結果ではありません。投入がコールバックで中止された場合などは`false`になり、投入エラーが例外として伝わる場合もあります。結果はジョブの中でDBに保存したり、Action Cableなどで通知したりして扱います。

### retry\_onの上限に達したジョブはどうなりますか？

例外がバックエンドまで伝わり、Solid Queueでは失敗済みジョブとして`solid_queue_failed_executions`に残ります。`after_discard`で記録するか、Mission Control Jobsの画面から再実行・破棄します。

### Solid QueueはRedisなしで本番運用できますか？

できます。Rails 8.0以降の既定構成はRedisを使わず、PostgreSQL・MySQL・SQLiteのキュー用DBにジョブを保存します。スループットが頭打ちになった段階でSidekiqを検討すれば足ります。

## 関連記事

- [Sidekiqとは？Rails 8.1での導入・リトライ・Web UI設定【Sidekiq 8.1.7】](/tech/details/7843/)
- [Active Job Continuationsとは？Rails 8.1のstep・cursorでジョブを中断・再開する方法](/tech/details/8853/)
- [Shoryuken（Ruby gem）とは？SQSワーカーの導入・設定とActive Job連携・リトライ設計【7.0.4対応】](/tech/details/3429/)
- [request specとは？Rails 8・RSpec 8でのリクエストスペックの書き方](/tech/details/3993/)
- [ActiveRecord 7.2の変更点｜トランザクションコールバック・attributes\_for\_inspect・with\_connectionを実行して比較](/tech/details/10104/)

---

出典: [Rails Active Jobとは？perform\_laterとSolid Queue・retry\_onの使い方【Rails 8.1.4】](<https://www.issoh.co.jp/tech/details/3988/>)（株式会社一創）
