good_jobを導入して定時実行のジョブ(cron)を実装する手順、全体像

# 実装に必要な最低限の知識

good_jobとは
Ruby on Railsアプリケーションでバックグラウンドジョブを実行するためのGemです。

https://github.com/bensheldon/good_job

<br>

good_jobはActive_jobを基本としているので、忘れていたらActive_jobについてさらっと目を通すと理解が深まります。

https://railsguides.jp/active_job_basics.html


# 実際の手順

未来の自分のために手順をそのまま残しておきます。

## 初期設定

### gemを導入
```Gemfile
gem 'good_job'
```

```terminal
bundle install
```

<br>

### good_jobがRailsアプリケーションに統合されるための初期設定
ターミナルでコマンドを実行します。
```terminal
bundle exec rails generate good_job:install
```

このコマンドで、いくつかファイルがgenerateされます。
まず1つ目にマイグレーションファイルが生成されます。


https://railsguides.jp/active_job_basics.html

先ほどの記事の内容になりますが、
ジョブを実行する際は通常、Ruby on Railsアプリケーションの他にバックエンドインフラを起動して準備しておく必要です。
good_jobではApplicationで使用しているデータベースでキューを管理することができるようにするので、そのために必要なジョブテーブルをDBに作成するためのマイグレーションファイルが作成する必要があります。

ということでマイグレーションファイルを生成したらそのままマイグレートします

```
bundle exec rails db:migrate
```


<br>

2つ目に'config/initializers/good_job.rb'ファイルも生成されます。こちらでgood_jobの設定（定時処理の設定)を行うことができますが一旦スルーします。


### ActiveJobのバックエンドをGoodJobに変更

次にconfig/application.rbにてActivejobの実行をgood_jobに変更します。

```config.rb
module HogeHogeApplication
  class Application < Rails::Application
      config.active_job.queue_adapter = :good_job # この行を追記
  end
end
```

これで最低限の初期設定は完了しました。

<br>

## config/initializers/good_job.rbにて定時にジョブを実行するように設定(cronジョブの設定)

こちらの記事を参考にしました

https://madogiwa0124.hatenablog.com/entry/2022/10/08/125502

先ほどのgenerateコマンドで自動生成されたconfig/initializers/good_job.rbに必要な初期設定をしていきます。

```good_job.rb
Rails.application.configure do
  config.good_job[:enable_cron] = true # good_jobが実行できる様々なジョブの内、cronを有効にしている
  config.good_job[:cron] = {
    my_hoge_task: { # 有効にしているcronジョブの名前
      cron: '0 0 * * *', # 毎日深夜0時に実行
      class: 'MyHogeTaskJob' # my_hoge_taskジョブで実行するJobクラスを指定
    }
  }
end
```

good_jobでは、

cron　定期的なスケジュールに沿って実行されるジョブ。cronはギリシャ語で'時間'
one_off　　一度だけ実行されるジョブ
retryable　　ジョブの実行が失敗した場合に自動的にリトライするジョブ
priority　　ジョブに優先順位をつけて自動的にリトライするジョブ
queue　ジョブを特定のキューに配置して異なる処理順序などで実行するジョブ

このような種類のジョブを実行することができます。今回は`「毎晩深夜0時に実行されるジョブ」`を実装したかったので`cronジョブ`を設定しました。

```
cron: '0 0 * * *'
```

については、
- **`0`** 分: 毎時0分に実行
- **`0`** 時: 毎日0時（つまり、夜中の12時）に実行
- **`*`** 日: 月のすべての日に実行
- **`*`** 月: 年のすべての月に実行
- **`*`** 曜日: 週のすべての曜日に実行

ということを意味しています。これで定期でジョブを実行するように設定できました。


## 実際にジョブを実装する
app/jobs/my_hoge_task_job.rbに最低限のジョブを実装します。
こちらのファイルではどのバッチ処理ファイルを行うかを定義して、詳細はバッチ処理専用のファイルに持たせることが一般的らしい

app/jobs/my_hoge_task_job.rb
```my_hoge_task_job.rb
class MyHogeTaskJob < ApplicationJob
  queue_as :default #Active Jobフレームワークにおいて、ジョブがどのキューに入れられるかを指定

  def perform
     MyHogeTaskBatch.new.call #詳細を持たせたMyHogeTaskBatchをnewして、callメソッドを実行
  end
end

```

app/batches/my_hoge_task_batche.rbのcallメソッドに詳細な処理内容を実装。

```my_hoge_taks_batch.rb
class MyHogeTaskBatch
  def call
    実行したい処理
  end
end
```

## テストコードについて
spec/jobs/my_hoge_task_job_spec.rbにモックを使用したテストを書きました

モックを使用したテストの実装について、過去に自分がまとめた記事

https://qiita.com/hosomatu/items/f14e97c2101529b685cb


MyHogeTaskJobの動作確認は
「MyHogeTaskBatchのの詳細を隔離したまま、batchという代替品にcallメソッドが届くかどうかの確認をする」という方法でテストをしています。

spec/jobs/my_hoge_task_job_spec.rb

```my_hoge_task_job_spec.rb
require 'rails_helper'

RSpec.describe MyHogeTaskJob do
  it 'MyHogeTaskBatchのインスタンスが生成されcallメソッドが呼び出される' do
    batch = MyHogeTaskBatch.new
    allow(MyHogeTaskBatch).to receive(:new).and_return(batch)
    allow(batch).to receive(:call)
    described_class.perform_now
    expect(batch).to have_received(:call)
  end
end
```

もちろん、詳細なテストもspec/batches/my_hoge_taks_batch_spec.rbに書きます。

```my_hoge_taks_batch_spec.rb
require 'rails_helper'

RSpec.describe MyHogeTaskBatch do
  describe '#call' do
    subject { described_class.new.call }
    詳細な内容を確かめるテスト
  end
end
```

## まとめ
以上のような手順でgood_jobを使用してcronジョブを実装できました。
初学者の書いた記事なので、間違っている場合があります。そのときはご指摘していただけると大変助かります