2020年5月8日金曜日

ActiveJobの処理でファイルを添付していると performed_jobs が想定より1件多くなる?(Ruby on Rails, Minitest, ActiveStorage)

遭遇した現象

こちらを参考に、Jobが1件実行されたことを確認するテストを書いてみました。
https://api.rubyonrails.org/classes/ActiveJob/TestHelper.html#method-i-assert_performed_jobs

# download_job_test.rb

require "test_helper"

class DownloadJobTest < ActiveJob::TestCase
  setup do
    @my_image = my_images(:one)
  end

  # (省略)

  test "perform download job" do
    assert_performed_jobs 0
    perform_enqueued_jobs  do
      DownloadJob.perform_later(@my_image.id)
    end
    # Jobが1件実行されたことを確認する
    assert_performed_jobs 1
  end
end

ところが実行してみると、何故か2件のJobが実行されてFailします。

$ bin/rails test test/jobs/download_job_test.rb
Run options: --seed 59411

# Running:

F

Failure:
DownloadJobTest#test_perform_download_job [/mnt/c/Users/Owner/workspace/my_app/test/jobs/download_job_test.rb:23]:
1 jobs expected, but 2 were performed.
Expected: 1
  Actual: 2


rails test test/jobs/download_job_test.rb:17

.

Finished in 1.342921s, 2.2339 runs/s, 2.2339 assertions/s.
3 runs, 3 assertions, 1 failures, 0 errors, 0 skips

調べたこと

performed_jobs で実行されたJobが確認できるようなのでとりあえず出力してみる。

参考:
https://api.rubyonrails.org/classes/ActiveJob/QueueAdapters/TestAdapter.html#method-i-performed_jobs

Provides a store of all the performed jobs with the TestAdapter so you can check them.

# download_job_test.rb

    perform_enqueued_jobs  do
      DownloadJob.perform_later(@sound_info.id)
      p performed_jobs # この行を追加
    end

結果

[{:job=>DownloadJob, :args=>[502201877], :queue=>"default"}, {:job=>ActiveStorage::AnalyzeJob, :args=>[{"_aj_globalid"=>"gid://my_app/ActiveStorage::Blob/88"}], :queue=>"default"}]

ActiveStorage::AnalyzeJob という覚えのないJobが実行されている…?
そのまま「ActiveStorage::AnalyzeJob」で検索してみると、どうやらActiveStorageが自動的に追加するJobの様子。

参考:
https://edgeapi.rubyonrails.org/classes/ActiveStorage/AnalyzeJob.html

ActiveStorage::AnalyzeJob
Provides asynchronous analysis of ActiveStorage::Blob records via ActiveStorage::Blob#analyze_later.

https://edgeguides.rubyonrails.org/active_storage_overview.html#analyzing-files

Active Storage analyzes files once they've been uploaded by queuing a job in Active Job.

https://blog.kozakana.net/2018/03/try_active_storage/

先にkeyが作られてJobで後からアップロード処理される様です。

https://stackoverflow.com/questions/56445881/rails-how-to-disable-activestorage-analyzers-and-previewers

There is no easy way to disable Analyzers completely

たしかにJobの中で、外部からダウンロードした画像ファイルをActiveStorageを使用してレコードに添付している箇所がありました。
この添付処理を行っている箇所をコメントアウトするとテストが通るので、ここが原因で間違いなさそう。

# download_job.rb

class DownloadJob < ApplicationJob
  queue_as :default

  def perform(my_image_id)
    # (省略)

    # download_url からダウンロードした画像ファイルをmy_imageレコードに添付
    open(download_url) do |file|
      my_image.downloaded_image.attach(io: file.open, filename: "downloaded.png", content_type: "image/png") # この行をコメントアウトするとテストが通る
    end

    # (省略)
  end
end

対処

この ActiveStorage::AnalyzeJob が登録・実行されること自体はRailsのデフォルトの挙動で問題ないようなので、テストではJob名を指定して件数をカウントすることにしました。

# download_job_test.rb

  test "perform download job" do
    assert_performed_jobs 0
    perform_enqueued_jobs  do
      DownloadJob.perform_later(@my_image.id)
    end
    # DownloadJobが1件実行されたことを確認する (:only オプションを追加)
    assert_performed_jobs 1, only: DownloadJob
  end

環境

ruby 2.6.2
Rails 6.0.2.1
delayed_job (4.1.8)
minitest (5.14.0)

0 件のコメント:

コメントを投稿