Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥

ActiveJobUpdates

 ActiveJobUpdates

Active Job 近況 - Continuations, Solid Queue
Kuniaki Igarashi / igaiga
RailsTokyo #2

Avatar for Kuniaki IGARASHI

Kuniaki IGARASHI

December 18, 2025
Tweet

More Decks by Kuniaki IGARASHI

Other Decks in Technology

Transcript

  1. ステップ定義コード例 class SomethingJob < ApplicationJob include ActiveJob::Continuable # Continuations機能を使う def

    perform # ステップをブロックで定義 step :first do |step| # ブロック引数stepへActiveJob::Continuation::Stepオブジェクトが渡ってくる end # ステップをメソッドで定義 step :second private def second(step) # 引数stepへActiveJob::Continuation::Stepオブジェクトが渡ってくる end end
  2. ステップらがどのように実行されるかの確認コード(中断なし) class SomethingJob < ApplicationJob include ActiveJob::Continuable def perform puts

    "=== Start/Resume Job" # ステップに属さないコード step :first do |step| # ステップ puts "=== 1st step" end puts "=== Middle point" # ステップに属さないコード step :second # ステップ puts "=== Finish Job" # ステップに属さないコード end private def second(step) puts "=== 2nd step" end end
  3. 実行結果(中断なし、初回) === Start/Resume Job # ステップに属さないコード(初回も再開時も常に実行される) === 1st step #

    ステップ === Middle point # ステップに属さないコード === 2nd step # ステップ === Finish Job # ステップに属さないコード ステップのコードおよびステップ外のコードが書いた順に実行される ステップに属さないコードは初回も再開時も常に実行される ステップのコードは前回実行されていたらスキップされる
  4. ジョブを中断させるサンプルコード secondメソッド(2番目のステップ)を書き換えて初回実行時にジョブを中断させる step.resumed? : 再開実行されているかどうかを判断 ActiveJob::Continuation::Interrupt : ジョブを中断させる例外 def second(step)

    # step: ActiveJob::Continuation::Stepオブジェクト # step.resumed?: 再開実行かどうか unless step.resumed? # 初回だけ raise ActiveJob::Continuation::Interrupt.new # 中断させる end puts "=== 2nd step" end
  5. ステップらがどのように実行されるかの確認コード(中断あり) class SomethingJob < ApplicationJob include ActiveJob::Continuable def perform puts

    "=== Start/Resume Job" # ステップに属さないコード step :first do |step| # ステップ puts "=== 1st step" end puts "=== Middle point" # ステップに属さないコード step :second # ステップ (初回だけ中断させる) puts "=== Finish Job" # ステップに属さないコード end private def second(step) # step: ActiveJob::Continuation::Stepオブジェクト unless step.resumed? # 初回だけ raise ActiveJob::Continuation::Interrupt.new # 中断させる end puts "=== 2nd step" end end
  6. 実行結果(2ndステップで中断、その後再開) # 初回 === Start/Resume Job # ステップに属さないコード(毎回実行) === 1st

    step # ステップ === Middle point # ステップに属さないコード # ここで実行される2nd stepで中断 # 5秒待ってからジョブが再開する # 2回目 === Start/Resume Job # ステップに属さないコード(毎回実行) === Middle point # 1st stepは実行済みなのでスキップされている === 2nd step # ステップ === Finish Job # ステップに属さないコード
  7. カーソルの初期値 初回実行時のカーソル初期値はnil step :first do |step| p step.cursor #=> nil

    # 初期値はnil ステップ定義に start: 引数を書くと、初回の初期値を設定できる step :first, start: 1 do |step| p step.cursor #=> 1 # 初期値はステップ定義のstartオプションでの指定値 再開時のカーソル値は、前回中断した時の最後の値
  8. 初回時と再開時のカーソル値 step :first do |step| p "=== step.cursor #=> #{step.cursor}"

    step.set! (step.cursor || 0) + 1 # カーソル値に1を足す p "=== step.cursor #=> #{step.cursor}" raise ActiveJob::Continuation::Interrupt.new unless step.resumed? end # 初回 "=== step.cursor #=> " # 初回の初期値はnil "=== step.cursor #=> 1" # 再開時 "=== step.cursor #=> 1" # 再開時は前回終了時の値 "=== step.cursor #=> 2"
  9. カーソル機能を使うコード例(配列の各要素を処理) step :first, start: 0 do |step| # カーソル初期値を0にする items[step.cursor..].each

    do |item| # で説明 item.do_something # 今回のitemを処理 step.advance! # カーソルをsuccして進める end end items[step.cursor..] 初回 step.cursor: 0 items配列の先頭から処理開始 再開時 step.cursor: 前回終了時の値 items配列の未作業の要素から処理を再開
  10. ジョブクラスにContinuationsの設定を書く class SomethingJob < ApplicationJob self.resume_options = { wait: 1.seconds,

    queue: :resumed } self.max_resumptions = 3 wait(再開までの時間): デフォルトは5.seconds queue(中断時に入れるキュー): デフォルトは初回と同じ max_resumptions(最大再開回数): デフォルトはnil、無制限に再開可能 注意: ActiveJobには以前からContinuations機能とは別のリトライ機能がある リトライ設定 retry_on StandardError, attempts: 3 と組み合わせ注意 retry_jobメソッド: Continuations機能の中断再開 retry_onメソッド: 従来のリトライ 設定値詳細: https://api.rubyonrails.org/classes/ActiveJob/Continuation.html
  11. isolatedオプションによる明示的なキュー再投入 「ジョブをキューへ保存できない異常終了時は、再開できない」を緩和する機能 isolatedオプション: ステップ開始前に必ずジョブ(進捗情報付き)をキューに保存 ステップ定義で step :some_step, isolated: true とisolatedオプション指定

    チェックポイント間隔を短く設定できない、時間がかかるステップのときに有用 そのステップの開始前に進捗情報を記録したジョブをキューに保存する ジョブがキューに保存され、再開してからそのステップを実行する
  12. Railsの練習帳 今日の内容はRailsの練習帳へ書きました Railsの練習帳 Active Job Continuations https://zenn.dev/igaiga/books/rails-practice-note/viewer/active_job_continuations Active Job Continuations

    参考資料 Railsガイド Active Jobの基礎 https://railsguides.jp/active_job_basics.html RailsAPI Active Job Continuation https://api.rubyonrails.org/classes/ActiveJob/Continuation.html RailsAPI Active Job Continuation Step https://api.rubyonrails.org/classes/ActiveJob/Continuation/Step.html
  13. Solid Queue Rails8.0新機能 DBをキューとして使うActive Job用バックエンド DBとしてMySQL、PostgreSQL、SQLiteなどが利用可能 FOR UPDATE SKIP LOCKED

    句を使える場合はパフォーマンスが上げる ジョブをポーリングする時のブロックやロック待ちを回避 使えない場合もパフォーマンスは落ちるがSolid Queueは使える Rails8.0以降のproduction環境ではデフォルトでSolid Queueが使われる rails new した直後から使えるのが便利
  14. Solid Queue 今日の説明の流れ Solid Queue 設定概要 Solid Queue を使ってみる Mission

    Control Jobs ジョブの定期実行 Solid Queue へ移行すべきか?
  15. Solid Queue 設定の概要 development環境でSolid Queueを使う設定 全部を説明すると長くなるので抜粋して説明します おおまかな流れ config/database.yml: queue用の設定を追加 マイグレーション実行:

    bin/rails db:migrate:queue Solid Queue設定ファイル: config/queue.yml 設定全体はRailsの練習帳に書いたのでこちらを読んでください https://zenn.dev/igaiga/books/rails-practice-note/viewer/solid_queue
  16. config/database.ymlへqueue用の設定を追加 development: primary: <<: *default database: storage/development.sqlite3 queue: <<: *default

    database: storage/development_queue.sqlite3 migrations_paths: db/queue_migrate SolidQueue用の queue キーを追加 通常DBとは別のDBを指定できる キー名 queue は設定に書いた名前 :queue と同じにする config.solid_queue.connects_to = { database: { writing: :queue } } マイグレーション実行: bin/rails db:migrate:queue スキーマファイル: db/queue_schema.rb
  17. Solid Queueを使ってみる rails consoleを起動してジョブをキューへ追加 この状態ではキューへ追加はされるが、まだジョブ実行はされない irb> AsyncLogJob.perform_later(message: "from Solid Queue")

    略 Enqueued AsyncLogJob (Job ID: 略) to SolidQueue(default) with arguments: {:message=>"from Solid Queue"} 略 bin/jobs start コマンドでバックエンド処理プロセスを起動してジョブ実行 デフォルトではログは log/development.log へ出力 bin/jobs コンソールには何も表示されない config/environments/development.rbへlogger設定を追加すると表示可能 config.solid_queue.logger = ActiveSupport::Logger.new(STDOUT)
  18. Mission Control Jobs mission_control-jobs Gem https://github.com/rails/mission_control-jobs Active Jobアダプター向けのキューの状態を確認するWeb UI 現在はSolid

    QueueとResqueがサポートされている ジョブキューやキュー内で待機中のジョブを確認する機能 失敗したジョブの情報閲覧、再試行、破棄する機能 適切なアクセス制限を追加する必要がある デフォルトではBASIC認証がかかっている 参考: TechRachoさん README翻訳記事 https://techracho.bpsinc.jp/hachi8833/2025_10_27/145131
  19. Mission Control Jobs 設定の流れ Gemfileへ gem "mission_control-jobs" を追加 config/routes.rb へ追加

    mount MissionControl::Jobs::Engine, at: "/jobs" デフォルトでBASIC認証がかかる BASIC認証用のuser, password情報をcredentialsへ設定 bin/rails credentials:editで以下を追加 mission_control: http_basic_auth_user: your_user http_basic_auth_password: your_password rails sを起動、http://localhost:3000/jobs へアクセス
  20. ジョブの定期実行 Solid Queueはcronのようなジョブを定期実行する仕組みも提供 スケジューラは solid_queue_recurring キューへジョブを投入 設定ファイル: config/recurring.yml config/recurring.yml production:

    clear_solid_queue_finished_jobs: command: "SolidQueue::Job.clear_finished_in_batches(sleep_between_batches: 0.3)" schedule: every hour at minute 12 デフォルト設定: 「完了ジョブを消すジョブ」を12分ごとに繰り返し実行 各タスクはジョブのクラスまたはコマンドを指定 各タスクのschedule設定はfugit Gemの文法で書ける
  21. ジョブ定期実行の細かい話 ジョブが重複してキューに入らないような仕組みが用意されている 複数マシンでアプリケーションサーバを起動しているケースを想定 同じ設定で複数のスケジューラが実行されるが、ジョブは重複しない ジョブ投入時のトランザクションでDBテーブルにレコード作成 solid_queue_recurring_executions テーブル task_key (タスク識別キー)と run_at

    (実行時刻)でユニーク制約 結果、同時刻の同一タスクについては1つのジョブしか作成されない preserve_finished_jobs設定がtrue (デフォルト) のときに動作 スケジュール設定ファイルconfig/recurring.ymlは1つだけ 複数のスケジューラが同じスケジュールを使う 複数のスケジューラで異なる設定を使うことはできない
  22. Solid Queue へ移行すべき? 非同期ジョブをこれから導入するならば便利で有力な選択肢 既にSidekiqなどを使っている場合、Solid Queue へ移行すべき? 参考: willnetさん Kaigi

    on Rails 2024 "Sidekiq vs Solid Queue" https://kaigionrails.org/2024/talks/willnet/ 移行メリットがあるのは脱Redisしてサーバコスト削減するケースなど限定的かも 性能はSidekiqの方が良いが、Solid Queueもそれなりの性能を出せる SidekiqはSolidQueueの15倍速い Sidekiq wiki Solid Queueで2000万件/日のジョブを処理 on HEY Rails8.0 release note キュー監視、エラー監視などの移行も必要
  23. Railsの練習帳 Solid Queue https://zenn.dev/igaiga/books/rails-practice-note/viewer/solid_queue Solid Queue 参考資料 Solid Queue README

    https://github.com/rails/solid_queue Railsガイド Active Jobの基礎 https://railsguides.jp/active_job_basics.html TechRacho Rails: Mission Control Jobs gem README(翻訳) https://techracho.bpsinc.jp/hachi8833/2025_10_27/145131
  24. 宣伝: お仕事募集中 Railsの業務委託のお仕事を週1〜2日程で探してます ↓ 業務内容の例( 「こんなこともできる?」とご相談いただけましたら) ペアプロ屋、著書 パーフェクトRailsやRailsの練習帳などでの読書会や講義 書籍、ドキュメント、講演資料の書き方解説やレビュー Active

    Job導入の設計相談や実装 RubyとRailsのバージョンアップ実装作業、レガシーコード改善実装 コードの健康診断とレポート CTO経験にもとづく経営相談 ガーネットテック373株式会社 業務内容詳細ページ、問い合わせページ ← こちらから気軽にご相談ください