LoginSignup
3
2

More than 1 year has passed since last update.

[Rails]ActiveJobについて、、!

Last updated at Posted at 2020-11-01

ActiveJobとは、、?

ジョブを宣言し、それによってバックエンドでさまざまな方法によるキュー操作を実行するためのフレームワーク。Active Jobを利用することによって、メールの送信や、バッチ処理などをバックグラウンドで実行することが可能になります。

ActiveJobの予備知識

キュー

first in, first outのデータ構造。スタックの逆。

ジョブ

定期的なクリーンアップを始めとして、請求書発行やメール配信など、あらゆる処理がジョブになる。これらのジョブをより細かな作業単位に分割して並列実行することもできる。

Active Jobの目的

  • Delayed JobとResqueなどのように、さまざまなジョブ実行機能のAPIの違いを気にせずにジョブフレームワーク機能やその他のgemを搭載することができるようになる。
  • バックエンドでのキューイング作業では、操作方法以外のことを気にせずに済む。
  • ジョブ管理フレームワークを切り替える際にジョブを書き直さずに済む。

Resque

  • RMagickなどのメモリリークが存在するコードでも不安なくデプロイできる。
  • エコシステムが出来上がってる。
  • 毎回forkするので長時間ジョブ向き。
  • キューのストレージとしてRedisが必要。
  • メンテが追いついてない。

Delayed Job

  • DMに専用テーブル作成が必要。
  • メモリリークしてるコードがあれば定期的な再起動が必要。

Sidekiq

  • Resque互換API。
  • 並列に動作するので、外部サイトへのAPI呼び出しなど、I/O待ちの比率が大きいような用途で使うのに便利。
  • 1個のプロセスで動作させられるのでメモリ使用量が少なく経済的。
  • プロセス肥大化には弱い。
  • コネクションプールの扱い。
  • 並列以外の扱い。

Jobの実装

渡されたメッセージをDBレコードに保存する非同期ジョブ機能を実装する。

1.ジョブクラスを生成する。

rails g job async_log

2.生成したジョブクラスを実装する。

class AsyncLogJob < ApplicationJob
  # 保存するキューを指定
  queue_as :default

  # 実行したい処理を記載する
  def perform(message: "hello")
    AsyncLog.create!(message: message)
  end
end

3.ジョブをキューに入れる。(コンソールで実行する)

irb(main):001:0> AsyncLogJob.perform_later
#=> バックエンドキューにジョブを追加し、非同期実行する

# ジョブが実行されたか確認する
irb(main):002:0> AsyncLog.first
#=> #<AsyncLog id: 1, message: "hello", created_at: "2021-07-11 06:26:24.405744000 +0000", updated_at: "2021-07-11 06:26:24.405744000 +0000">

ジョブ実装時のTips

実行するタイミングを指定する

# 5分後に処理が実行される
AsyncLogJob.set(wait: 5.minute).perform_later

# 翌日に処理が実行される
AsyncLogJob.set(wait_until: Date.tomorrow).perform_later

複数キューの管理をする

1.追加するキューを指定する。

class AsyncLogJob < ApplicationJob
  # 追加するキューを指定する
  queue_as :async_log # デフォルトではdefaultが指定されている
  ...
end

2.キューの一覧を作成する。

config/sidekiq.yml
:queues:
  - default # デフォルト使用するキュー
  - async_log # 追加したキュー
  - mailers # Action Mailerで利用するキュー

ジョブへ渡す引数の制限

  • NilClass
  • String
  • Integer
  • Float
  • BigDecimal
  • TrueClass
  • FalseClass
  • Symbol
  • 日時を扱う型(ActiveSupport::TimeWithZone, Time, Date, ActiveSupport::Durationなど)
  • Hash(キーはStringかSymbol)
  • Array
  • Active Recordオブジェクト

バックエンドの設定

デフォルト設定では、プロセスの再起動時にジョブが失われるなど、本番環境向きではないため、Sidekiqを使う。

1.Gemfile二以下を追記して、bundle installを実行する。

gem 'sidekiq'

2.アダプターを設定する。
※環境別で変更したい場合は、config/environments/***.rbに記載する。

config/application.rb
module WebpackerSample
  class Application < Rails::Application
    ...
    config.active_job.queue_adapter = :sidekiq
    ...
  end
end

ジョブの例外処理

ジョブのリトライ

app/jobs/async_log_job.rb
class AsyncLogJob < ApplicationJob
  ...
  # 補足する例外を指定し、必要であればオプションを指定する
  retry_on StandardError, wait: 5.seconds, attempts: 3
end

利用できるオプション

オプション名 概要 デフォルト値
wait リトライまで指定時間待つ 3.seconds
attempts リトライ回数 5
queue リトライ時に追加するキュー nil
priority 優先度 nil

ジョブの破棄

app/jobs/async_log_job.rb
class AsyncLogJob < ApplicationJob
  ...
  # 指定したエラーが発生した場合にジョブを破棄する
  discard_on StandardError
end

3.Redis環境をセットアップする。

$ docker pull redis

$ docker run -p 6379:6379 redis

4.Sidekiqを起動する。

$ bundle exec sidekiq

5.キューの状態を確認するUIを開発環境限定で閲覧可能とする。

config/routes.rb
Rails.application.routes.draw do
  ...
  if Rails.env.development?
    require 'sidekiq/web'
    mount Sidekiq::web => '/sidekiq'
  end
  ...
end

利用判断基準

ActiveJobを利用してSidekiq(等の非同期バックエンド)を使うか、Sidekiq(等の非同期バックエンド)のAPIを直接使うかの判断に迷った場合は下記を参照する。

ActiveJobを使うと良いケース

  • 標準的な機能のみ使用する
  • プロジェクト初期段階でバックエンド選択をまだしていない
  • バックエンドを差し替える可能性がある
  • ActiveJobに依存している機能(Action Mailerなど)を使う
  • ActiveRecordオブジェクトをキューへ追加するときに、デフォルトで用意されているGlobal IDを使った変換処理を利用する

非同期バックエンドを使うと良いケース

  • ActiveJobから使えない機能がある場合
    • Sidekiqでは外部gem、Sidekiq Proなどが提供している機能)

参考

Rails 4.2で導入されたActive Jobを使ってみよう

【Rails, Linux】『Active Job』と『ジョブ』についてまとめてみた

Active Jobの基礎

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2