Rails 7.1: 複数ジョブを一度にエンキューするperform_all_laterが追加(翻訳)
このブログ記事はRails 7シリーズの一環です。
Rails 7.1に、複数のジョブを一度にエンキューするActiveJob.perform_all_later
メソッドが追加されました。このメソッドはジョブインスタンスの配列を受け取ります。Active Recordのバルク系メソッドと同様に、perform_all_later
もコールバックを実行しません。
たとえば、メールを複数ユーザーに送信したい場合は以下のように書けます。
welcome_email_jobs = users.map do |user|
WelcomeEmailJob.new(user)
end
ActiveJob.perform_all_later(welcome_email_jobs)
perform_all_later
を使うことで、usersのレコードをループで処理してからperform_later
を実行するよりも、キューデータストアへのラウンドトリップ回数を減らせます。つまり、キューイングバックエンドがSidekiqの場合は、Redisのラウンドトリップのレイテンシを削減できます。
PostgreSQLを利用するGoodJobなどをキューイングバックエンドに使っている場合は、perform_all_later
ですべてのジョブが1個のINSERT文でエンキューされるので、パフォーマンスがさらに高まります。
ただし、キューイングバックエンドがバルク(一括)エンキューをサポートしていない場合は、個別のジョブをエンキューする形にフォールバックするのでご注意ください。
Active Jobはさまざまなジョブ処理ライブラリの違いを抽象化するよう設計されているので、インターフェイスが統一されています。このしくみは、Active Jobがサポートしている多くのアダプタによって実現されています。
キューイングバックエンドの中でも人気の高いSidekiqでは、push_bulk
メソッドがすでにサポートされています。プルリク#46603の作者は、Sidekiqアダプタを変更することでこのperform_all_later
メソッドでSidekiqのpush_bulk
メソッドを利用可能にしました。
なお、最近GoodJobにもバルクキューイング機能が追加されました(#790)。
実際のActiveJob.perform_all_later
が有用なのは、数千件ものジョブを一度にキューに流し込みたい場合のみです。一度にエンキューするジョブ数が少ない場合、パフォーマンス上のメリットはさほどありません。
詳しくは#46603をご覧ください。
概要
元サイトの許諾を得て翻訳・公開いたします。
日本語タイトルは内容に即したものにしました。
参考: 週刊Railsウォッチ20230314: 複数ジョブを一度にエンキューするperform_all_laterが追加