Rails 8のSolid Queue:Sidekiqに代わる新しい非同期処理システム

こんにちは!Webアプリケーションエンジニアのレミーです!

この記事はEnigmo Advent Calendar 2025の21日目の記事です。

Rails 8がリリースされてから、バックグラウンドジョブシステムである Solid Queue に興味を持ち、調べてみました。

バックグラウンドジョブは、Ruby on Railsアプリケーションに重要な部分です。メール送信、画像処理、データ同期、キャッシュ更新、CSVファイルのエクスポートなど、これらはすべてアプリケーションの高速化とスムーズな動作を維持するために非同期で実行すべきタスクです。

長年、Railsのバックグラウンドジョブにおいて「Sidekiq + Redis」はほぼ基準とされてきました。しかし、Rails 8からは、Railsは公式にSolid Queueを導入しました。これはRedisを必要とせず、補助的なサーバーも不要な、ネイティブなキューシステムです。

この記事では、Solid Queueとは何か、その仕組み、どうしてRails 8以上のプロジェクトでSolid Queueを使用すべきかについて解説します。また、Sidekiqとの比較も行います。

Solid Queueとは?

Solid Queueは、データベースをジョブキューとして使用するバックグラウンドジョブシステムであり、Rails Solid Suite(Solid Cache, Solid Queue, Solid Cableを含む)の一部として開発されました。

Redisを使用するSidekiqとは異なり、Solid Queueはジョブをデータベースのテーブルに保存し、ワーカープロセスがそのジョブを読み取って実行します。

つまり:

  • Redisが不要
  • Sidekiqのインストールが不要
  • 補助サーバーのコストがかからない
  • ActiveJobと深く統合されている
  • インストールが非常に簡単

これは、Railsをシンプルにするために生まれました。特にスタートアップ、小規模〜中規模のプロジェクト、またはコストを抑える必要がある環境に最適です。

仕組みとデータベース構造

Solid Queueは単一のシンプルなテーブルだけではなく、ジョブのライフサイクルを管理し、安全性とパフォーマンスを確保するために複数のテーブルを使用します。

重要なテーブルは以下の通りです:

  • solid_queue_jobs: ジョブのメタデータ(クラス名、引数、キュー名、優先度、遅延ジョブの場合はscheduled_at、ジョブIDなど)を保存します。
  • solid_queue_ready_executions: 「実行準備完了」となったジョブを含みます。つまり、エンキューされたジョブで、ワーカーが拾える状態のものです。
  • solid_queue_scheduled_executions: スケジュールされたジョブを含みます。まだ実行タイミングには達していません。
  • solid_queue_claimed_executions: ワーカーが実行のために確保)したジョブ情報を保存し、複数のワーカーが同じジョブを実行しないためです。
  • solid_queue_blocked_executions: ブロックされており、すぐに実行できないジョブを含みます。
  • solid_queue_failed_executions: 実行後にエラーになったジョブを保存し、監視やデバッグに役立ちます。

このように明確に複数のテーブルに設計されているため、Solid Queueは役割を明確に分離でき、ロジックがクリアになり、管理しやすくなります。

Solid Queueにおけるジョブのライフサイクル

Solid Queueの仕組みと、なぜ複数の異なるテーブルが必要なのかを理解するために、ジョブがエンキューされ、ワーカーに拾われ、実行され、削除されるまでの完全なライフサイクルを説明します。

1. ジョブが呼び出される時(エンキュー)

MyJob.perform_later(args) を呼び出すと、Solid Queueはデータベースに対して2つの書き込み操作を行います:

  • solid_queue_jobs テーブルへの書き込み:ジョブのメタデータ("queue_name", "class_name", "arguments", "priority", "active_job_id", "scheduled_at", "finished_at", "concurrency_key" など)を保存します。
  • すぐに実行するジョブの場合:solid_queue_ready_executions にデータを追加します。このテーブルには、ワーカーが処理可能な準備完了ジョブが含まれます。

2. ワーカーが実行するジョブを探す(ポーリング)

ワーカーは solid_queue_ready_executions テーブルを継続的に「ポーリング」して、新しいジョブを取得します。ワーカーは以下の2つの作業を行います:

  1. 確保: ワーカーが solid_queue_ready_executions からジョブを選択すると、solid_queue_claimed_executions テーブルにレコードを書き込みます。このレコードにより、2つのワーカーが同じジョブを実行することができません。
  2. 実行: クレームした後、ワーカーはジョブクラスの perform メソッドを呼び出して実行します。

3. ジョブ完了時、レコードの削除

ジョブが正常に実行されると、ワーカーは関連するすべてのテーブル(solid_queue_jobs, solid_queue_ready_executions, solid_queue_claimed_executions)からジョブを削除します。

ジョブのライフサイクルの簡単なまとめ

段階 関連テーブル 目的
ジョブのエンキュー solid_queue_jobs ジョブのメタデータを保存
ジョブ準備完了 solid_queue_ready_executions ワーカーが拾える状態
ワーカーによる確保 solid_queue_claimed_executions 1つのジョブを1つのワーカーが実行することを保証
実行 なし ワーカーが perform関数を呼び出す
完了 複数のテーブルから削除 レコードのクリーンアップ

安全性、ジョブの「失う」を防ぐ仕組み

重要な要件の一つは、エンキューされたジョブが少なくとも1回は実行され、失われないことです。Solid Queueは、ワーカーのクラッシュ、強制終了、プロセスの不具合などのケースを以下の形式で処理します:

  • 各ワーカーは起動時に solid_queue_processes にレコードを作成し、定期的に last_heartbeat_at を更新します。
  • ワーカーがジョブをクレームする際、solid_queue_claimed_executions にプロセスIDと共にレコードを書き込みます。
  • デフォルトはスーパーバイザープロセスがバックグラウンドで実行され、processes テーブルをチェックします。許容時間を超えて heartbeatがないプロセス(例:5分以上)が見つかった場合、それを「失敗したワーカー」と見なします。
  • スーパーバイザーはそのプロセスを削除し、そのワーカーが保持していたジョブを ready キューに再エンキューして、他のワーカーが拾えるようにします。

これにより、ワーカーがクラッシュしてもジョブは失われず、データの整合性が保証されます。

Solid Queue と Sidekiq の比較

Solid QueueとSidekiqはどちらもRailsで人気のある非同期処理のシステムですが、以下の表で違いを明確にします。

基準 Solid Queue (Rails 8) Sidekiq
ストレージバックエンド データベース (PostgreSQL / MySQL / SQLite) Redis (インメモリ、非常に高速)
Railsとの統合 ネイティブ、Rails 8からの公式組み込み コアじゃない、gem経由で使用
パフォーマンス 小〜中規模のワークロードに良好 非常に高い、大規模ワークロードに最適
遅延 DB使用のため比較的高い 低い (Redis インメモリ)
インストール 簡単、補助サービス不要 複雑、RedisとSidekiqの設定が必要
運用コスト ほぼゼロ (既存DBを使用) Redisのコストがかかる (特に本番環境)
信頼性 高い (SQLトランザクション + ジョブクレーム) 非常に高いがRedisに依存
リトライのロジック あり、DBに保存 あり、強力かつ柔軟
ダッシュボード 強力なUIはまだない Web UIが充実、リアルタイム監視が可能

いつ Solid Queue を選ぶべきか?

シンプル、軽量、ネイティブ、コスト節約を望むならSolid Queueを選びましょう。

いつ Sidekiq を選ぶべきか?

高速、強力、大規模システムに適したものを望むならSidekiqを選びましょう。

結論

Solid Queueは、インフラを簡素化し、Rails 8の大きな進歩を示しています。バックグラウンドジョブをコアフレームワークに直接統合することで、中小規模のプロジェクトはRedisやSidekiqに依存する必要がなくなり、安定性、信頼性の高いジョブ処理能力を確保しながら、運用コストを大幅に削減できます。

明日の記事の担当はエンジニアの宮川さんです。お楽しみに。