Railsで不定期タスクを簡単に管理する：Sidekiqの活用法

# 1.	はじめに
自分は10月よりAPPRENTICE SHIP(内定直結型エンジニア学習プログラム)のカリキュラムに２期生として参加しています。
この記事はオリジナルアプリ開発の際に使用した、Sidekiqの備忘録として書いています。
間違いがありましたらご指摘いただけると幸いです
#### 読者対象
- Ruby初学者の方
- これからSidekiqを使おうか悩んでいる方
- RubyまたはRailsで非同期処理を行おうとしている方
- 不定期な時間で動く処理を実装しようとしている方
以上がこの記事の対象者となります。
# 2.	Sidekiqとは？
 [Sidekiq公式リファレンス](https://github.com/sidekiq/sidekiq)
SidekiqとはRubyで非同期処理を簡単に実装するためのライブラリになります。
#### 補足:そもそも非同期処理って？
- 簡単に言えば、サーバーのタイミングをみて手隙の時間に処理してもらう方法です。他の処理とタイミングが被っても他の処理が止まりません。
- 逆に同期処理にしてしまうと、重い処理を走らせた時に、完了するまで何もしてくれなくなります。。。

# 3.	Sidekiqの使い道
上で説明したとおりに、Railsで非同期処理を実現するライブラリです。
今回作成したアプリケーションではSidekiqのpeform_atを主に使い、ユーザーの動的スケジュールを実装できる様にしました。
実装例でいうと、ユーザーが予約した時間にお知らせLINEが飛んだり、アラートメールを送信したりするのに使用しました。
# 4.	Redisとは？
Sidekiqでは非同期ジョブのキュー管理に高速なデータアクセスが必要なため、メモリ上にデータを保持するRedisを用意する必要があります。
Redisとはメモリイン型のデータベースになり、NoSQLというカテゴリに位置するものです。
RDBとは違い、ストレージに**メモリ**を使用して高速化をしているデータベースになります。

# 5.	簡単な用語解説と処理の流れ
### 簡単な用語解説
- **キュー(queue)**
実行を待機しているジョブのリストのことです。Sidekiqでは、ジョブがキューに追加され、順番に処理されます。キューにより、複数のジョブを効率的に管理し、順序よく実行することが可能になります。

- **ワーカー(worker)**
実際にジョブを処理するバックグラウンドのプロセスです。Sidekiqを使用する際には、ワーカークラスを定義し、どのような処理を行うかを記述します。ワーカーはキューからジョブを取り出し、定義されたタスクを実行します。

- **スケジュール(schedule)**
ジョブを将来の特定の時点で実行するためのタイミングを指定することです。perform_atやperform_inのようなメソッドを使用して、ジョブが実行されるべき正確な時間または将来のある時点までの遅延時間を設定できます。これにより、ユーザーが指定した時刻にメールを送信するなど、タイミングを指定したジョブの実行が可能になります

- **ジョブ(job)**
ジョブとは、バックグラウンドで実行されるべきタスクや作業の単位を指します。

### 処理の流れ
1. ジョブをスケジュールする: ある特定のジョブ（例えば、ユーザーにリマインダーを送信するタスク）を特定の時刻に実行するようスケジュールします。これはperform_atやperform_inメソッドを使って行うことができ、ジョブをキューに追加するタイミングを制御します。

2. キューをセットする: スケジュールされたジョブは、実行されるべき時刻が来た時に、実行待ちのジョブのリストであるキューに追加されます。Sidekiqはこのキューを監視し、ジョブが実行可能になるとそれを取り出します。

3. ワーカーを起動させる: キューからジョブが取り出されると、Sidekiqのワーカープロセスがそのジョブを取得し、定義されたタスク（この例ではリマインダーの送信）を実行します。ワーカーはバックグラウンドで動作し、メインのアプリケーションプロセスに影響を与えることなくジョブを処理します。


# 4. 環境構築
### 1. Docker環境を用意
まずは、Dockerで立ち上げたRails環境を用意しdocker-compose.ymlにredis環境を記述してください。
*ここではrailsの立ち上げ手順は省きます。
```docker-compose.yml
version: '3.8'
services:
  redis:
    image: redis:7.2.4-alpine
    volumes:
      - redis-data:/data
    ports:
      - "6379:6379"
    # 以下、railsやデータベースの設定は用意してください。

```
### 2. RailsのSidekiqをインストール
```Gemfile
gem 'sidekiq"
```
上記をGemfileに追記してbundle installを実行します。

### 3.設定ファイル
./config/initalizers内にsidekiq.rbファイルを用意してサーバーとクライアントの設定を記述します。
``` sidekiq.rb
# frozen_string_literal: true

Sidekiq.configure_server do |config|
  config.redis = { url: ENV['REDIS_URL'] || 'redis://localhost:6379/0' }
  config.logger = Logger.new('log/sidekiq.log')
end

Sidekiq.configure_client do |config|
  config.redis = { url: ENV['REDIS_URL'] || 'redis://localhost:6379/0' }
end
```

# 5. 使い方
Sidekiqを実際に使用する方法について解説します。

### 1. Workerディレクトリを用意
Railsアプリケーションのappディレクトリ内にworkersディレクトリを作成します。
このディレクトリは、Sidekiq workerクラスを格納する場所になります。
```
mkdir app/workers
```
### 2. Workerファイルを記述
workersディレクトリ内に、実行したいバックグラウンドジョブのロジックを含むRubyクラスファイルを作成します。例えば、reminder_worker.rbというファイルを作成し、以下のような内容を記述します。

```reminder_worker.rb
class ReminderWorker
  include Sidekiq::Worker

  def perform(user_id, message)
    user = User.find(user_id)
    # ユーザーにリマインダーメッセージを送信するロジック
  end
end
```
### 3. Workerの呼び出し
作成したWorkerを実際に呼び出してジョブを実行します。perform_asyncメソッドを使って即時にジョブを実行するか、perform_atやperform_inメソッドを使って将来の特定の時点でジョブを実行するようスケジュールします。

perform_async: ジョブを即座にキューに追加し、実行します。
第１引数にキューを識別する一意の値を入れます。

```perform_async.rb
ReminderWorker.perform_async(user.id, "こんにちは！")
```
perform_atとperform_in: ジョブを特定の時刻に実行するようスケジュールします。  
第1引数に実行する時間、第2引数にキューを識別する一意の値を入れます。
```perform_at.rb
ReminderWorker.perform_in(5.days, user.id, "リマインダーです！")
ReminderWorker.perform_at(5.days.from_now, user.id, "リマインダーです！")
```
# 6. Sidekiq UIについて
Sidekiqには、実行中のジョブ、キューの状態、失敗したジョブなどを監視し、管理するためのWebインターフェイスが用意されています。このインターフェイスを利用するには、config/routes.rbファイルに以下のようなルーティングを追加します。


```router.rb
require 'sidekiq/web'
mount Sidekiq::Web => '/sidekiq'
```
これにより、Railsを立ち上げたポートのアドレス末尾に/sidekiqをつけると、Sidekiqのダッシュボードにアクセスできるようになります。
![スクリーンショット 2024-03-29 11.29.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954214/7153ad2d-1c2c-7464-2126-df68efffff56.png)
このダッシュボードからキューのスケジュールや、成功、失敗、再試行などをモニターすることができます。

## 7.所感
この記事を最後までお読みいただき、ありがとうございました。
簡単にですが、オリジナルアプリを作成した際に使用したSidekiqについて紹介させていただきました。
記述も少なく、任意の時間で処理を実行できるのでとてもありがたいですね。

まだ、エラーハンドリングや、テストなど紹介しきれていませんが今回は割愛させていただきます。
Redisなど別途サーバーを用意しなければなりませんが、似た様な機能を実装する上でかなり強力なライブラリだと思いました。
また、機会があれば続きを書きたいと思います。