mcpField
R
rails-jobs

rails-jobs

github.com/marckohlbrugge開発73055 回インストール20 週間前に更新
リポジトリ

rails-jobs について

rails-jobsは、Railsのバックグラウンドジョブを設計・レビューするスキルです。安全な再試行、キュー、定期処理、エラー処理、テストの指針を扱います。

主な機能

  1. 01浅く冪等なジョブ設計
  2. 02キューとペイロードの指針
  3. 03再試行とエラー処理のパターン
  4. 04定期処理と一括処理のパターン
  5. 05非同期動作のテスト指針

活用シーン

  1. 01ジョブの再試行安全性のレビュー
  2. 02キューとテナントコンテキスト処理の設計
  3. 03長時間処理や定期処理の計画

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/marckohlbrugge/37signals-skills --skill rails-jobs

インストール後、Claude Code で/rails-jobsを入力して読み込まれたか確認します。

詳細

Rails ジョブ

バックグラウンドジョブの設計とレビューに使用します。Campfire(Resque、薄いジョブを4つ)と Fizzy(Solid Queue、複数キュー)のパターンです。

デフォルト

  • ジョブは浅く保ちます。ジョブ本体はモデルメソッドを呼び出す1行にします:def perform(card) = card.notify_recipients。
  • ジョブを冪等にし、安全に再試行できるようにします(例:ドメイン操作内で RecordNotUnique を rescue する)。
  • 実際のエラーは明確に失敗させ、エラーを握りつぶすパターンは避けます。
  • アプリのデフォルトで ActiveJob::Base.enqueue_after_transaction_commit = true を設定します。これにより、ジョブがデータより先に実行される競合を根本から解消できます。
  • 新規アプリでは、Redis ベースのキューより Solid Queue(データベースベース)を優先します。小規模なデプロイでは Puma と同居させます(SOLID_QUEUE_IN_PUMA)。

命名規則

  • _later はエンキュー、プレーンな名前は処理を実行し、明示的に同期実行する対のメソッドが必要な場合は _now を使います:
def notify_recipients          # the work — public API the job calls
def notify_recipients_later   # enqueues NotifyRecipientsJob (often private, called from callbacks)
  • エンキュー時のコンテキストはキーワード引数として取得します(Mention::CreateJob.perform_later(self, mentioner: Current.user))。実行時の Current に依存しないでください。
  • マルチテナントアプリでは、すべてのジョブにテナントのコンテキストをシリアライズします。エンキュー時に Current.account を(GlobalID として)取得し、perform_now を Current.with_account でラップする ApplicationJob 拡張を先頭に追加します。

推奨パターン

  • ジョブのペイロードは小さく保ちます。レコード(GlobalID)または ID を渡し、大きなオブジェクトグラフは渡しません。
  • 重要度に応じてキュー(default、backend、webhooks)を分け、キュー設定で優先順位を明示します。
  • オーケストレーションジョブと重い処理を行うジョブを分離します。
  • 負荷の急増が同期して発生しないよう、定期ジョブは分単位の端数(12、27、50分)にずらして実行します。
  • 一括エンキュー:due.in_batches { |batch| ActiveJob.perform_all_later(batch.map { DeliverJob.new(it) }) }。
  • ActiveJob::Continuable を使用して、長い反復処理をクラッシュに耐えられるようにします。step :dispatch + find_each(start: step.cursor) + step.advance! は、ファンアウト(webhook、ブロードキャスト、バックフィル)に不可欠です。
  • limits_concurrency to: 1, key: ->(owner) { owner }(Solid Queue)を使って、所有者ごとの処理を直列化します。
  • ファンアウトの多い HTTP 処理(ウェブプッシュ)では、2段階の非同期処理にします。ドメインイベント用のジョブを実行し、その後、インプロセスのスレッドプールで HTTP 呼び出しを行います。プールに投入する前にすべての AR データを解決し、バックプレッシャーが発生した場合は RejectedExecutionError で破棄します。
  • after_destroy_commit の非同期処理では、before_destroy で必要な関連データのスナップショットを取得します。ジョブの実行時には親レコードが削除されている可能性があります。

定期処理とメンテナンス

  • 定期タスクでは専用のジョブクラスではなく、モデルクラスの通常のメソッドを呼び出します(command: "MagicLink.cleanup")。
  • 保持期間を過ぎたデータの一括削除には、スコープに対する delete_all(stale.delete_all)を使います。古いレコードのコールバックはスキップします。
  • 完了済みのキュージョブ、期限切れトークン、古い配信レコードをクリーンアップする処理をスケジュールします。
  • cron によるリセットより、使用時のリセットを優先します。スケジュールされたジョブではなく、ドメインメソッド内で確認してリセットします(spend が reset_if_due を呼び出す)。
  • ベータ環境やステージング環境では、定期スケジュールを必須のものに絞ります。

エラー処理の方針

  • 一時的な失敗(タイムアウト、DNS、Net::SMTPServerBusy)は retry_on ..., wait: :polynomially_longer で再試行します。
  • 恒久的な失敗は再試行しません。rescue して、エラークラスやメッセージで分類し、:info レベルでログに記録します(想定内のエラーです。宛先不明、メールボックスが満杯など)。成功する可能性のある処理のために、ジョブキューのリソースを確保します。
  • 「宛先側で失敗した」(結果を記録してジョブを完了する)場合と、「コード側で例外が発生した」(エラーとしてマークし、再試行のために再度 raise する)場合を区別します。rails-webhooks を参照してください。
  • エラー分類を Concern としてパッケージ化し、フレームワークのジョブに include します(ActionMailer::MailDeliveryJob.include SmtpDeliveryErrorHandling)。

テスト

  • 単純なジョブクラスはユニットテストしません。モデルのテストで perform_enqueued_jobs(only: Mention::CreateJob) { ... } と assert_enqueued_with(job: ...) を使い、非同期動作をテストします。
  • ジョブの内部ではなく、観測可能な結果(メンションが作成された、メールが送信された)を検証します。

危険な兆候

  • 複雑な分岐やビジネスルールが直接埋め込まれたジョブ。
  • ガードのない、冪等でない副作用。
  • 恒久的に無効な入力の再試行。
  • 必要なレコードがコミットされる前のジョブのエンキュー。
  • エンキュー時にシリアライズせず、perform 内で Current.user/Current.account を読み取ること。
  • perform_all_later や Continuable による反復処理が適している場面で、ループ内で項目ごとに perform_later を呼び出すこと。
  • 使用時にリセットするロジックのほうがシンプルで安全なのに、Cron 形式のリセットジョブを使うこと。
  • バックグラウンドジョブによって不要な Turbo ブロードキャストが発生すること(suppressing_turbo_broadcasts で囲みます)。

コメント