RailsとGoodJob: PostgreSQLベースのバックグラウンドジョブプロセッサ
Railsアプリケーションで、時間のかかる処理(メール送信、画像処理、外部APIへのリクエストなど)をユーザーのリクエストサイクルから切り離して非同期に実行するためには、バックグラウンドジョブの仕組みが不可欠です。RailsにはActive Jobという標準APIがあり、そのバックエンドとしてSidekiqやResqueといった様々なライブラリを選択できます。
これらのライブラリの多くは、ジョブキューの管理にRedisを利用します。しかし、アプリケーションのインフラにRedisを追加することは、管理すべきコンポーネントが一つ増えることを意味します。
もしあなたのアプリケーションがすでにPostgreSQL(Postgres)をプライマリデータベースとして利用しているなら、GoodJobは非常に魅力的な選択肢となります。
GoodJobは、Active Jobのバックエンドとして機能し、PostgreSQLだけを使ってバックグラウンドジョブを実現するライブラリです。
この記事では、GoodJobの特徴と、SidekiqなどのRedisベースのプロセッサとの違いについて解説します。
GoodJobとは? なぜPostgreSQLなのか?
GoodJobの最大の特徴は、ジョブの永続化とロックの仕組みに、PostgreSQLの堅牢な機能を活用している点です。
FOR UPDATE SKIP LOCKED
: このPostgresの高度なロック機能を使うことで、複数のワーカースレッド/プロセスが同じジョブを同時に取得しようと競合することなく、効率的にジョブをキューから取り出すことができます。- トランザクション保証: ジョブの状態変更はPostgresのトランザクション内で安全に行われます。これにより、ジョブが失われたり、不整合な状態になったりするリスクが極めて低くなります。
- インフラの簡素化: 新たにRedisを導入・運用・監視する必要がありません。すでに使い慣れたPostgresのバックアップやフェイルオーバーの仕組みをそのまま活用できます。
GoodJobの主な特徴
- Active Jobとの完全な互換性: Active JobのAPI(
perform_later
,set
,perform_now
など)に完全準拠しています。 - マルチスレッド/マルチプロセス対応: アプリケーションの要件に応じて、スレッドベースまたはプロセスベースのワーカースタイルを選択できます。
- ダッシュボード: ジョブの実行状況、キューの状態、エラーになったジョブなどを確認できるWeb UIが組み込まれています。
- 柔軟な設定: キューごとの優先順位付け、スレッド数の調整、cronライクな定期実行(Scheduled Jobs)など、豊富な設定が可能です。
- 非同期実行モード:
async
モードを使えば、Webプロセス(Pumaなど)と同じプロセス内でジョブを実行できます。小規模なアプリケーションであれば、専用のワーカーカープロセスを起動する必要さえありません。
セットアップ方法
1. インストール
Gemfile
にgood_job
を追加してbundle install
を実行します。
# Gemfile
gem "good_job"
2. マイグレーション
GoodJobがジョブを管理するためのテーブルを作成するマイグレーションを実行します。
rails g good_job:install
rails db:migrate
3. Active Jobバックエンドの設定
config/application.rb
または環境ごとの設定ファイルで、Active Jobのバックエンドに:good_job
を指定します。
# config/application.rb
class Application < Rails::Application
# ...
config.active_job.queue_adapter = :good_job
end
4. ワーカースタイルの選択と実行
config/good_job.yml
(または環境変数)で、ワーカースタイルやキューの設定を行います。
実行コマンド:
# デフォルト設定でワーカを起動
bundle exec good_job start
# Pumaのプラグインとしてインプロセスで実行(別途設定が必要)
bundle exec puma -C config/puma.rb
5. ダッシュボードの有効化
config/routes.rb
にダッシュボードのマウント設定を追加します。
# config/routes.rb
Rails.application.routes.draw do
# ...
mount GoodJob::Engine => 'good_job'
end
これで/good_job
にアクセスすると、ダッシュボードが表示されます。
GoodJob vs. Sidekiq (Redisベース)
GoodJob (PostgreSQL) | Sidekiq (Redis) | |
---|---|---|
外部依存 | PostgreSQLのみ | PostgreSQL + Redis |
インフラ | シンプル | 比較的複雑 |
一貫性 | 強い(DBのトランザクション) | 限定的(Redisの性質による) |
パフォーマンス | 非常に高いが、Redisには劣る | 一般的に最速 |
機能 | Active Job準拠、ダッシュボード | 非常に多機能(Pro/Enterprise版) |
ユースケース | 堅牢性、シンプルさが重要な場合 | 超高スループットが求められる場合 |
どちらを選ぶべきか?
GoodJobが適しているケース:
- インフラをできるだけシンプルに保ちたい。
- ジョブの消失リスクを極限まで低くしたい(強い一貫性が求められる)。
- 1秒あたり数千ジョブといった超高スループットは必要ない。
- ほとんどの一般的なWebアプリケーションはこちらに該当します。
Sidekiqが適しているケース:
- 1秒あたり数万件以上のジョブを処理する必要があるなど、パフォーマンスが最優先事項である。
- Redisの運用経験が豊富である。
- Sidekiq Pro/Enterprise版が提供する高度な機能(バッチ処理、レートリミットなど)が必要である。
まとめ
GoodJobは、多くのRailsアプリケーションにとって、バックグラウンドジョブの仕組みを導入するための、非常に堅実で現実的な選択肢です。
- PostgreSQLだけで完結するため、インフラがシンプルになる。
- DBのトランザクションに裏打ちされた、高い信頼性を持つ。
- Active Jobに準拠しており、学習コストが低い。
Redisを導入する明確な理由(特にパフォーマンス要件)がない限り、まずはGoodJobを検討してみることを強くお勧めします。データベースという、すでによく知っている技術の上に構築される安心感と、運用のシンプルさは、開発チームにとって大きなメリットとなるでしょう。