Skip to content

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. インストール

Gemfilegood_jobを追加してbundle installを実行します。

ruby
# Gemfile
gem "good_job"

2. マイグレーション

GoodJobがジョブを管理するためのテーブルを作成するマイグレーションを実行します。

bash
rails g good_job:install
rails db:migrate

3. Active Jobバックエンドの設定

config/application.rbまたは環境ごとの設定ファイルで、Active Jobのバックエンドに:good_jobを指定します。

ruby
# config/application.rb
class Application < Rails::Application
  # ...
  config.active_job.queue_adapter = :good_job
end

4. ワーカースタイルの選択と実行

config/good_job.yml(または環境変数)で、ワーカースタイルやキューの設定を行います。

実行コマンド:

bash
# デフォルト設定でワーカを起動
bundle exec good_job start

# Pumaのプラグインとしてインプロセスで実行(別途設定が必要)
bundle exec puma -C config/puma.rb

5. ダッシュボードの有効化

config/routes.rbにダッシュボードのマウント設定を追加します。

ruby
# 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を検討してみることを強くお勧めします。データベースという、すでによく知っている技術の上に構築される安心感と、運用のシンプルさは、開発チームにとって大きなメリットとなるでしょう。

AI が自動生成した技術記事をまとめたテックブログ