RailsアプリにDockerを導入した③【redisコンテナ&sidekiqコンテナ】

## やったこと
Railsアプリに、RedisコンテナとSidekiqコンテナを載せた。

## なんのために？
- 非同期処理：時間のかかるタスクやある時間になったら実行したいタスクを「後で処理するリスト」に入れておき、他のタスクを実行しながら「後で処理するリスト」のタスクも並列で行っていく
- 「後で処理するリスト」には __Redis__ のキューがよく使われる。これから処理していく予定のジョブのデータをRedisに永続化することで、Railsプロセスが落ちたとしてもエンキューされたジョブのデータは失われない
- Railsサーバと __Redis__ と __Sidekiq__ の関係：Railsサーバの処理の中で「後で処理するリスト」に任せたいジョブがあれば、 __Redis__ で永続化しているキューにジョブを追加（エンキュー）し、 __Sidekiq__ がジョブを取り出して（デキュー）実行していく
- ↑これらのキュー操作をさまざまな方法で実行するためにインターフェースなどを定めているフレームワークがActive Job


## 手順
1. ローカルで動かす
1. SidekiqとRedisの詳細設定
1. 動作確認

### ローカルで動かす
Redisをインストールし、Redisサーバーを起動
（起動させた状態で、Sidekiqを実行していく）
```bash
$ brew install redis
$ redis-server
```
Sidekiqのインストールと実行
```sh
# Gemfileにsidekiqを追加後
$ bundle 
$ bundle exec sidekiq
```
Redis, Sidekiqの起動を確認できたら詳細設定をしていく。

### SidekiqとRedisの詳細設定

#### RailsとSidekiqの連携
development環境では、sidekiqを、test環境ではtestをキューアダプターに設定し、環境によって非同期処理の挙動を変える。
```rb
# config/environments/development.rb
config.active_job.queue_adapter = :sidekiq
```

```rb
# config/environments/test.rb
config.active_job.queue_adapter = :test
```
#### Redisの場所を定義
sidekiq server: キューからjobを取ってきて実行する役割
sidekiq client: キューにjobを追加する役割
([参考](https://shuofeng.dev/understanding-background-jobs-sidekiq/))
```rb
# config/initializers/sidekiq.rb
Sidekiq.configure_server do |config|
  config.redis = { url: ENV['REDIS_URL'] }
end

Sidekiq.configure_client do |config|
  config.redis = { url: ENV['REDIS_URL'] }
end
```
#### Sidekiqのルーティング追加
Sidekiqのダッシュボードにアクセスできるように設定。
(`mount`: 本体アプリケーションから独立したアプリケーションのルーティングを定義)
```rb
# config/routes.rb
if Rails.env.development?
    require 'sidekiq/web'
    mount Sidekiq::Web, at: '/sidekiq'
end
```
#### Sidekiqのジョブのオプション設定
- ジョブの同時実行数を５にしてクラッシュ回避（デフォルトは10）
- ジョブは全て`default`キューに入るようにする

```yml
# config/sidekiq.yml
:concurrency: 5
:queues:
  - default
```
#### コンテナ定義
sidekiqコンテナとredisコンテナを定義する。
```yml
# docker-compose.yml　追加分
  web:
    environment:
      REDIS_URL: redis://redis:6379

  sidekiq:
    build: . # webコンテナと同じイメージを使用
    environment:
      REDIS_URL: redis://redis:6379
    volumes:
      - .:/karoyaka:cached
      - bundle:/usr/local/bundle
    depends_on:
      - db
      - redis
    command: bundle exec sidekiq

  redis:
    image: redis:latest
    ports:
      - 6379:6379
    volumes:
      - redis:/data

volumes:
  redis:
```


### 動作確認
コンテナ起動させ、サンプルジョブを作成し、コンテナ再起動し、サンプルジョブを認識させる。
railsコンソールでジョブを登録して、ダッシュボード（`http://localhost:***/sidekiq`）確認。
```bash
$ docker-compose up
$ docker-compose run web rails g sidekiq:job sample
$ docker-compose up
$ docker-compose run web rails c
irb(main)> SampleJob.perform_async
```
sidekiqコンテナ、redisコンテナが正常に動作していることを確認できた :tada:

## 参考

- [Sidekiqってどんなキック？](https://dev.icare.jpn.com/dev_cat/sidekiq/)
- [Sidekiq GitHub](https://github.com/mperham/sidekiq/wiki/Using-Redis#using-an-initializer)
- [Rails 6の新しいデフォルト設定と安全な移行方法を詳しく解説（翻訳）](https://techracho.bpsinc.jp/hachi8833/2019_11_14/83047)(Active Storage + Sidekiq)]
- [Understanding Background Job in Rails with Sidekiq](https://shuofeng.dev/understanding-background-jobs-sidekiq/)
- [Sidekiqの導入手順【令和版】](https://blog.furu07yu.com/entry/rails-install-sidekiq-2022)
- [gem Sidekiqの導入](https://qiita.com/sazumy/items/dabd550e3f969f72d64c)
- [docker-composeでRails+PostgreSQL+Redis+Sidekiq環境を作る](https://snyt45.com/I54Z7umy_)