Railsの「ジョブ（Active Job）」についてまとめてみた

## Active Jobとは

- Railsの内部フレームワーク。
- ジョブを宣言し、バックエンドでさまざまな方法によるキュー操作を行うための共通インターフェース。

リンク:
- [Active Jobの基礎 -Railsガイド](https://railsguides.jp/active_job_basics.html)
- [Ruby on Rails 4.2 Release Notes 2 Major Features 2.1 Active Job](https://edgeguides.rubyonrails.org/4_2_release_notes.html#active-job)

### ジョブとは

- 「コマンドやプログラムがまとまった、ひとかたまりの処理」のこと。
    - 端末ごとに見た一連の処理。
    - プロセスが１つもしくは複数集まって１つのジョブができているイメージ。
    - プロセスと同様 `kill` コマンドで停止できる。
- コンピュータはマルチタスクなため、ジョブは並列実行することが可能。
- 例: メール送信、CSVアップロードなど。

##### フォアグラウンドジョブ

- 今操作しているアプリケーション。
    - 例: ChromeやFirefoxなどのブラウザ。

##### バックグラウンドジョブ

- フォアグラウンドジョブ以外のジョブ。
    - 例: ChromeやFirefoxなどのブラウザに対する端末。

リンク:
- [【一通りわかる】Linuxでのジョブの基本的な扱い方まとめ](https://eng-entrance.com/linux-job)

### バックエンド（バックグラウンド）とは

- ここではRailsのアプリケーションサーバー（Unicornやpumaなど）のプロセスとは別に、ジョブを実行するために立ち上げられるプロセスのこと。またはそのプロセスを立ち上げるキューイングシステム（DelayedJob、Resque、Sidekiqなど）。
- 非同期処理される環境。

リンク:
- [Resque、SidekiqからSucker PunchまでActiveJobのバックエンドについてひと通り調べてみた](https://chopschips.net/blog/2015/02/26/active-job/)
- [プロセスとスレッドについて調べた - Qiita](https://qiita.com/yokoto/items/3b4bcc489d93bc57baf3)

### キューとは
First in, first outのデータ構造。
※ 誤解を招く表現になりそうだが、取り出し方の決まっている配列のようなものというイメージ。

## Active Jobは何がうれしいのか？

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

## ジョブ管理フレームワークの種類

以下の3つはジョブキュー処理の主要gem。

#### Resque

##### 良い点

- RMagickなどのメモリリークが存在するコードでも不安なくデプロイできる。
- エコシステムが出来上がってる。

##### 悪い点

- 毎回forkするので長時間ジョブ向き。
- キューのストレージとしてRedisが必要。
- メンテが追いついてない。


#### Delayed Job

##### 良い点

- 特になし。

##### 悪い点

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


#### Sidekiq

##### 良い点

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

##### 悪い点

- プロセス肥大化には弱い。
- コネクションプールの扱い。
- 並列以外の扱い。

リンク:
- [ジョブキュー処理のResqueとDelayed Jobの使い分けの方針などはありますか？](https://web.archive.org/web/20190528225019/https://qa.atmarkit.co.jp/q/2406)
- [rubyで非同期処理](https://gist.github.com/hoco/9764412)
- [【Active Job】Sidekiq vs Resque vs Delayed Job - Zenn](https://zenn.dev/shima_zu/articles/rails_active_job)
- [【Rails】ActiveJob/DelayedJobを使いこなす【基本】](https://qiita.com/shunsuke227ono/items/c29119a348f120c5c13a)
- [SidekiqでRailsに非同期処理を実装するチュートリアル - Qiita](https://qiita.com/tachibanayu24/items/c97afa1a66217cdd064e)
- [Sidekiqの要点まとめと動かし方](http://tech-blog.tsukaby.com/archives/1519)
- [sidekiqを使用する際に注意したい覚え書き](https://attracie.hatenablog.com/entry/2015/10/18/200407)


## ジョブの作成

```shell
$ bin/rails generate job InvoiceIssuing
invoke  test_unit
create    test/jobs/invoice_issuing_job_test.rb
create  app/jobs/invoice_issuing_job.rb
```

```rb
class InvoiceIssuingJob < ApplicationJob
  queue_as :default

  def perform(*guests)
    # 後で実行するタスクをここに置く
  end
end
```

## ジョブの実行

### デフォルトのキューイングの振る舞い

- Rails自身がデフォルトで提供するのは、ジョブをメモリ（アプリケーションサーバーのプロセス内）に保持するキューイングシステムだけ。
    - プロセスがクラッシュしたりコンピュータをリセットしたりすると、デフォルトの非同期バックエンドの振る舞いによって主要なジョブが失われてしまう。
        - つまりバックグラウンドジョブやRailsのサーバー自体が止まったりする。
- アプリケーションが小規模な場合やミッションクリティカルでないジョブであればこれでも構いませんが、多くのproduction環境においては永続的なバックエンドを選ぶ必要がある。

### production環境のキューイング

- production環境でのジョブのキュー登録と実行では、「キューイングバックエンド」（= キューイング用のgem）を選び、起動しておく必要がある。
    - Sidekiq
    - Resque
    - Delayed Jobなど

## キュー

- 多くのアダプタでは複数のキューを扱える。
    - Active Jobを使うと、特定のキューに入っているジョブを制御したりできる。

## その他
### コールバック
ActiveRecordのコールバックと同じようにライフサイクル中にロジックをトリガできる。
### Action Mailer
代表的なジョブ。Active JobはAction Mailerと統合されているので、非同期メール送信を簡単に行える。