Railsのdelayed_jobがわけわかめなのでメモメモ

どうもこんにちは。

今回はRailsアプリケーションで使用しているdelayed_jobについてメモしていきます。

# delayed_jobってなに？

delayed_jobとは、「バックグラウンドで非同期処理をしてくれるrailsのライブラリ」です。

何に使えるかっていうと、「大量のジョブを処理する時」に使えます！

一番わかりやすい例だと、**大量のメール送信を一度に行うとかなり時間がかかってしまうため、小分けにして送信していく**という手法をとるために最適です。

# 導入方法

導入はGemを使用して行います。

## 1. Gemの追加

Gemfileに以下のコードを記述します。

```gemfile
gem 'delayed_job_active_record'
```

## 2. bundle installの実行

ターミナルで`bundle install`を実行します。

## 3. マイグレーションファイルの作成

ターミナルで`rails generate delayed_job:active_record`を実行します。

Delayed_jobは、DB上にテーブルを作成してジョブを管理しています。
DBにアクセスすれば溜まっているジョブを確認することもできます。

## 4. マイグレーションの実行

ターミナルで`rails db:migrate`を実行します。

## 5. ジョブの実行方法を設定

`config/application.rb`に以下を記述します。
これによって、ActiveJobのバックエンドとしてdelayed_jobを使用するように指定できます。

```ruby
class Application < Rails::Application
    # ...
    config.active_job.queue_adapter = :delayed_job
    # ...
end
```

## 6. ジョブの実行/停止

以下をターミナルで実行して、delayed_jobワーカーを起動して、ジョブを実行します。

```
bin/delayed_job start
```

また、停止するときは以下のコマンドです。

```
bin/delayed_job stop
```

# 使用方法

自分が使用している目的は、メール送信を小分けにして送信することです。今回はそれの使用方法について説明します。

## メール送信機能の実装

ある機能のあるタイミングでメール送信ジョブが実行されるようにコードを書いていきます。

以下のコードをメール送信したいタイミングのコントローラに記述します。（例えばコメント登録の後とか。。。）

```ruby
addresses = ["test01@mail.com", "test02@mail.com", "test03@mail.com"]
addresses.each do |address|
    NotificationMailer.send_mail(address).deliver_later
end
```

次に、`app/mailers/application_mailer.rb`に以下のコードを記述します。

```ruby
class ApplicationMailer < ActionMailer::Base
  default from: 'TEST <noreply@test.net>'
  layout 'mailer'
end
```

次に、`app/mailers/notification_mailer.rb`に`send_mail`メソッドを定義します。

```ruby
class NotificationMailer < ApplicationMailer
  default from: 'TEST <noreply@test.net>'

  def send_mail(send_to_address)
    return if send_to_address == []

    mail(to: send_to_address, subject: "テストメールです。")
  end
end
```

最後に、`app/views/notification_mailer`ディレクトリに`send_mail.html.erb`を作成して、以下のように記述します。

```erb
<!DOCTYPE html>
<html lang="ja" dir="ltr">
    <head>
        <meta content='text/html; charset=UTF-8' http-equiv='Content-Type'>
    </head>
    <body>
        <h3><%= "テストメールです。" %></h3>
        <p>これはテスト〜\nメール送信のテスト~</p>
        <br>
    </body>
</html>
```

## バッチ処理実装

次は、ジョブが実行されるようにバッチ処理を組みます。

バッチ処理には、`whenever`というGemを導入する必要があります。

その手順は以下の記事でわかりやすく説明されていたので、そちらを参照してください。

https://qiita.com/mmaumtjgj/items/19e866f31541abb6c614

`whenever`の設定の中で、`config`ディレクトリに`config/schegule.rb`というファイルを作成したと思います。

そこに、Production環境で実行したいコマンドを記述します。（以下は5分おきに実行するという例です。）

```ruby
every 5.minute do
  command "cd /var/app/current && export $(cat /opt/elasticbeanstalk/deployment/env) && bin/delayed_job start"
end
```

これで5分おきにDelayed_jobが実行されるようになりました。

## メール送信の指令はどのようにしてジョブのキューに入るの？

キューとは、ジョブの待ちタスク見たいなものです。

今回の例では、コントローラから「メール送信してくれー」と指示を出しましたが、実は`deliver_later`というメソッドがジョブのキューに入れる役割をしています。

そのため、メールが送信されるまでの順番はこうなります。

![スクリーンショット 2023-09-14 19.08.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711491/c0296389-a975-3e3a-fc37-a411da3059bc.png)

# デプロイ時に必要な操作

仕上げにデプロイ時に以下のコマンドを実行する必要があります。

```
# cronを書き換え
bundle exec whenever --update-crontab

# 正常に書き換えられているか確認
bundle exec crontab -e
```

これは、setupファイルを作成して自動実行でも、ssh接続してコマンド実行でもなんでもOKです。

# まとめ

今回はdelayed_jobについて紹介しました。

まだ理解が浅いので、ちょくちょく記事は書き換えると思いますが、参考になったらいいなぁと思います。

以上