Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
54
Help us understand the problem. What is going on with this article?
@jnchito

ActiveJobのperform_laterとperform_nowの違い

More than 1 year has passed since last update.

はじめに

ActiveJobのperformメソッドは、perform_laterperform_nowの2通りで呼び出すことができます(以下のコード例はRailsのAPIドキュメントから引用しました)。

class ProcessPhotoJob < ActiveJob::Base
  def perform(photo)
    photo.watermark!('Rails')
    photo.rotate!(90.degrees)
    photo.resize_to_fit!(300, 300)
    photo.upload!
  end
end

# perform_laterで呼び出す
ProcessPhotoJob.perform_later(photo)

# perform_nowで呼び出す
ProcessPhotoJob.perform_now(photo)

では、perform_laterperform_nowは具体的にどのような違いがあるのでしょうか?

ネットを検索してみたところ、意外と明確に説明してくれている資料がなかったので、独自にまとめてみることにします。

perform_laterとperform_nowの違いは何か

APIドキュメントには以下のような説明があります。

  • perform_laterは)ジョブをキューに入れ、キューが空き次第ジョブを実行する。(To enqueue a job to be performed as soon as the queuing system is free)
  • perform_nowは)キューに入ることなく即座に実行される。(A job can also be processed immediately without sending to the queue)

もう少し簡単にいうと、perform_laterは非同期的に実行され、perform_nowは同期的に実行されます。

具体的にどういう挙動の違いが現れるのか、次の項で確認していきます。

簡単なサンプルで比較してみる

perform_laterperform_nowの違いを確認するために、簡単なサンプルプログラムを作ってみました。(Railsのバージョンは5.2.3)

app/jobs/sample_job.rb
class SampleJob < ApplicationJob
  queue_as :default

  def perform(msg)
    puts "[JOB] start: #{msg}"
    # sleepを入れて時間がかかる処理であることをシミュレート
    sleep 3
    puts "[JOB] end: #{msg}"
  end
end
app/models/foo.rb
class Foo
  # 非同期的にSampleJobを呼び出すメソッド
  def execute_later
    puts '[RUNNER] execute_later start'
    SampleJob.perform_later('hello')
    puts '[RUNNER] execute_later end'
  end

  # 同期的にSampleJobを呼び出すメソッド
  def execute_now
    puts '[RUNNER] execute_now start'
    SampleJob.perform_now('nihao')
    puts '[RUNNER] execute_now end'
  end
end

perform_laterを呼び出した場合

perform_laterを呼び出した場合は次のような実行結果になります。

> foo = Foo.new
> foo.execute_later
[RUNNER] execute_later start
Enqueued SampleJob (Job ID: e6859c49-4ec4-41d2-820f-eef63615cc51) to Async(default) with arguments: "hello"
Performing SampleJob (Job ID: e6859c49-4ec4-41d2-820f-eef63615cc51) from Async(default) with arguments: "hello"
[RUNNER] execute_later end
[JOB] start: hello
[JOB] end: hello
Performed SampleJob (Job ID: e6859c49-4ec4-41d2-820f-eef63615cc51) from Async(default) in 3005.48ms

ご覧のとおり、Foo#execute_laterの実行が完了("[RUNNER] execute_later end"を表示)したあとに、SampleJob#performが実行されていることがわかります(非同期実行)。
そのため、Foo#execute_laterの呼び出し自体はすぐに完了します。

perform_nowを呼び出した場合

一方、perform_nowを呼び出した場合は次のような実行結果になります。

> foo = Foo.new
> foo.execute_now
[RUNNER] execute_now start
Performing SampleJob (Job ID: 9cd85c4c-e515-4d70-aeb7-ac915d7e745b) from Async(default) with arguments: "nihao"
[JOB] start: nihao
[JOB] end: nihao
Performed SampleJob (Job ID: 9cd85c4c-e515-4d70-aeb7-ac915d7e745b) from Async(default) in 3001.38ms
[RUNNER] execute_now end

こちらはFoo#execute_now内でSampleJob#performが即座に実行され、SampleJob#performの処理が完了してから、"[RUNNER] execute_now end"が出力されています(同期実行)。
SampleJob#performは3秒間スリープするようになっているため、Foo#execute_nowの実行時間も3秒以上かかることになります。

どう使い分けるのがよいか

ここまで説明した通り、ActiveJobではperform_laterperform_nowの2通りの呼び出し方があります。
では、この2種類のメソッドはどう使い分けるのがよいでしょうか?

基本的なユースケースではperform_laterを使うことが大半だと思います。
なぜなら、重たい処理(=時間のかかる処理)を非同期的に実行することが、ActiveJobを利用する主な動機になるはずだからです。

ですので、perform_nowはあまり使われないと思いますが、以下のようなユースケースでは例外的にperform_nowが必要になるかもしれません。

  • 通常は非同期実行するが、ある特定の条件下においては同期実行したい
  • rails consoleなどで、とりあえずジョブの動作確認がしたい

少なくとも、ActiveJobを作ったのにperform_nowでしか呼びだしていないようなコードがあれば、設計か実装に何か間違いがあるのかもしれません。

まとめ

というわけで、この記事ではActiveJobのperform_laterperform_nowの違いについて調べてみました。

簡単にまとめると、

  • perform_laterは非同期実行(呼び出し側はジョブの完了を待たずに先へ進む)
  • perform_nowは同期実行(呼び出し側はジョブの完了を待ち続ける)

ということになります。

54
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
jnchito
株式会社ソニックガーデンのRubyプログラマ。 「プロを目指す人のためのRuby入門( https://bit.ly/3wmJheK )」の著者。 および「Everyday Rails - RSpecによるRailsテスト入門 ( https://bit.ly/3rKqrKX )」の翻訳者。 プログラミングスクール「フィヨルドブートキャンプ」のメンターでもある。
sonicgarden
「お客様に無駄遣いをさせない受託開発」と「習慣を変えるソフトウェアのサービス」に取り組んでいるソフトウェア企業

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
54
Help us understand the problem. What is going on with this article?