ActiveJobとSidekiqによる非同期処理

1. なぜ非同期処理が必要か

  • レスポンス時間の短縮
    メール送信や画像処理、外部API呼び出しなど時間のかかる処理をバックグラウンドに逃がすことで、ユーザーへの応答を速く保てます。

  • 信頼性の向上
    ジョブキューに積むことで処理が失敗しても自動リトライでき、アプリ本体の安定性を高めます。

  • スケーラビリティの確保
    Webプロセスとは別にワーカーを水平スケールさせることで、ピーク時でも処理遅延を抑えられます。


2. ActiveJobの位置づけ

機能 概要
ジョブ定義 rails g job で生成されるクラスに perform を実装
呼び出し perform_later / set(wait: 10.minutes).perform_later など
アダプター :async:sidekiq:resque などを統一APIで切り替え
シリアライズ 引数・戻り値を JSON に変換(複雑なオブジェクトは独自シリアライザで対応)
コールバック before_perform / after_perform で前後処理や計測

ActiveJobは抽象レイヤです。実際の実行エンジン(“バックエンド”)を選べるため、開発中は :async、本番は :sidekiq という切替も容易です。


3. Sidekiqの特徴

  • スレッド並列処理(デフォルト5本、YAMLで調整)により高スループット

  • Redisベースのシンプルなデータ構造で高速キューイング

  • 自動リトライ(最大25回・エクスポネンシャルバックオフ)

  • Web UI でキュー量・失敗ジョブ・再試行ジョブを可視化(Rackアプリとしてマウント可能)

  • ミドルウェア によるロギング、統計計測、独自監視の拡張

  • Sidekiq Pro / Enterprise でバッチ、ジョブレート制限、信頼性キューなども利用可能


4. ActiveJob×Sidekiq 連携手順(基本)

  1. Gem追加

    ruby
    # Gemfile gem "sidekiq"
    bash
    $ bundle install
  2. アダプター設定

    ruby
    # config/application.rb config.active_job.queue_adapter = :sidekiq
  3. ジョブ作成

    bash
    $ rails g job send_user_report
    ruby
    # app/jobs/send_user_report_job.rb class SendUserReportJob < ApplicationJob queue_as :default # キュー名を切替え可 def perform(user_id) user = User.find(user_id) PdfGenerator.call(user) # 時間のかかるPDF生成 UserMailer.report(user).deliver_now end end
  4. 呼び出し

    ruby
    SendUserReportJob.perform_later(current_user.id)
  5. Sidekiq起動

    bash
    $ bundle exec sidekiq -C config/sidekiq.yml

    例:config/sidekiq.yml

    yaml
    :concurrency: 10 :queues: - critical - [default, 2] # 重み2 - low

5. 典型ユースケース

  • メール・プッシュ通知送信

  • サムネイル生成/動画トランスコード

  • 定期バッチ(CSVエクスポート、統計集計)

  • 外部API連携(決済、SNS投稿)

  • Webスクレイピング、全文検索用インデックス更新


6. エラー処理とリトライ設計

項目 ActiveJob Sidekiq
自動リトライ retry_on SomeError, wait: 5.seconds, attempts: 3 ジョブ毎の sidekiq_options retry: 5 または全体設定
デッドジョブ 無(独自実装) “Dead” タブに送られ保留。UIから再キュー可
Idempotency 重要(例:メール重複送信防止) Redisのsetnxunique-jobsで排他が実現可

ベストプラクティス

  • 失敗しても副作用が安全なよう idempotent に設計

  • 小さな単機能ジョブに分割してトランザクション範囲を縮小

  • 例外を握り潰さず再試行可能なエラーだけリトライ設定

  • 重いバッチほど別キューへ振り分けて優先度を保つ


7. 定期実行・スケジューリング

  • sidekiq-cron または sidekiq-scheduler を追加

  • 例(daily_report ジョブを毎日8:00実行):

    yaml
    # config/sidekiq_schedule.yml daily_report: cron: "0 8 * * *" class: "DailyReportJob" queue: reports
    ruby
    Sidekiq::Cron::Job.load_from_hash! YAML.load_file(Rails.root.join("config/sidekiq_schedule.yml"))

8. 監視・メトリクス

  • Web UImount Sidekiq::Web => '/sidekiq' で管理画面に統合

  • StatsD / Prometheus exporter でジョブ処理時間や失敗率を可視化

  • redis-cli で直接キュー残量確認 (LLEN queue:default)


9. 運用ベストプラクティスまとめ

  1. 環境ごとにRedis URLやキュー名を分離し、開発・本番を安全に切替える

  2. ジョブ引数はIDやプリミティブ型に限定してオブジェクト肥大を防ぐ

  3. ワーカー数は CPUコア数×Threads を基準にチューニング(I/Oバウンドの場合は多め)

  4. SIGTERMグレースフルシャットダウンを活用し、デプロイ時にジョブを安全停止

  5. 永続化が必要なジョブログはLogrageやStructured Loggingで一元管理


まとめ

ActiveJobはRails標準の抽象レイヤであり、Sidekiqは高性能ワーカーエンジンです。ActiveJob経由でSidekiqを採用すると、「コードはRails流の書き味で保ちつつ、高速・堅牢なバックグラウンド処理を得る」ことができます。メール送信や画像変換などの重い処理をジョブに逃し、アプリの応答性と信頼性を両立させましょう。

ChatGPT4o 生成日:2025/06/21