eviry tech & service blog

「株式会社エビリー」の社員ブログです。弊社では、クラウド型動画配信サービス「millvi」、ソーシャル動画データ及び分析サービス「kamui tracker」、YouTube総合メディア「かむなび」を開発・提供しています。https://eviry.com/

Railsで非同期処理の実装

これは旧eviry tech blogから移行した記事です。

こんにちは。kamui tracker開発のhashimotoです。

kamui trackerでは、外部APIを利用するリクエストで、外部サービスの状況によって時間がかかったり、タイムアウトしてしまう処理がありました。 いろいろ対処方法はあると思いますが、今回は時間のかかる処理をリクエストから分離し、バックグラウンドで非同期に処理することで対応しました。

Railsでの非同期処理を初めて導入したので、非同期処理の実装方法について紹介したいと思います。

Railsでの非同期処理

Railsでは非同期処理を実装するのに便利なgemがいくつかあり、有名どころだと、

  • sidekiq
  • rescue
  • delayed job

などがあります。

今回はdelayed jobと、Railsが提供するActive Jobという機能を利用して非同期処理を実装していきます。

Active Jobについて

Active Jobは、上記であげたような非同期処理を行うgemに対して共通のインターフェースを提供してくれる機能です。Active Jobを利用することで、どのgemを使っても同じように非同期処理が実装できるというメリットがあります。 また、Active Jobではこれらのgemを「アダプタ」と呼びます。 (参考:https://railsguides.jp/active_job_basics.html)

delayed jobについて

delayed jobは、非同期の処理(ジョブといいます)の管理方法として、データベースのテーブルを利用します。delayed jobを利用する場合、非同期で実行するジョブをテーブルに保存し、delayed job専用のワーカーがテーブルからジョブを取得して処理していく、という流れになります。 非同期のジョブの管理場所、管理方法をキュー、キューイングシステムといいます。つまり、delayed jobの場合キューはデータベースのテーブルになりますね。 (参考:https://github.com/collectiveidea/delayed_job)

実装

ここからは、ActiveJobとdelayed jobを利用した非同期処理の実装について説明します。

Active Jobで非同期で実行する処理を作成

まずは、Active Jobの機能で、非同期で処理するジョブを作ります。

rails g job Sample

app/job配下にsample_job.rbというジョブファイルが作成されました。このファイルに、非同期で実行させたい処理を書いていきます。

class SampleJob < ApplicationJob
  queue_as :default

  def perform(arg)
    # 非同期で実行させたい処理を書く
  end
end

次は、実行したいジョブをキューに登録します。

SampleJob.perform_later(arg)

登録されたジョブは、バックグラウンドのアダプタによって非同期に実行されます。

実行する時間を指定することも可能です。

# 明日の正午に実行
SampleJob.set(wait_until: Date.tomorrow.noon).perform_later(arg)

# 1時間後に実行
SampleJob.set(wait: 1.hour).perform_later(arg)

次に、今回はアダプタとしてdelayed jobを利用するので、delayed jobの設定方法について説明していきます。

※アダプタが設定されていない場合、デフォルトで入っているAsyncというアダプタが利用されます。Asyncアダプタでも非同期処理はされますが、railsアプリの再起動で実行中のジョブやキュー内のジョブは消えてしまうので、本番環境で使うべきではないです。

Delayed Jobの設定

まずはGemのインストールです。 delayed jobのワーカーの起動にdaemons Gemも必要なので合わせてインストールしておきます。

gem 'daemons'
gem 'delayed_job_active_record', '~> 4.1.0'

インストール完了後、下記コマンドで、設定ファイルやジョブを管理するテーブルを作成するマイグレーションファイルが出力されます。

rails g delayed_job:active_record

作成したマイグレーションを実行してジョブ管理テーブルを作成します。

bundle exec rake db:migrate

次に、config/application.rbにActiveJobで使用するアダプタにdelayed jobを設定します。これで、Active Jobはデフォルトでdelayed jobをアダプタとして利用するようになります。

config.active_job.queue_adapter = :delayed_job

ワーカーの起動

delayed jobではワーカーがジョブ管理テーブルのジョブを処理するので、ワーカーを起動します。

# ワーカー起動
bin/delayed_job start

# ワーカーストップ
bin/delayed_job stop

ワーカーが起動した状態でジョブを登録すると、ワーカーがキューに登録されたジョブを取得して実行してくれます。

以上で、非同期処理の作成 ~ 実行までができるようになりました!