Sidekiq 7の新機能・変更点

## はじめに

Ruby on Rails (以下Rails) でバックグラウンドジョブを実行する際に一番よく使われているのGemである、Sidekiqのバージョン7.0（以下Sidekiq 7）が2022年10月にリリースされました。

このバージョンでは、管理画面へのメトリクスの追加、Pumaなどのプロセスへの埋め込み、キュー毎の同時実行数を制限するカプセルなど、以前よりも大きな機能追加が行われています。

本記事では、Sidekiqの公式サイトの記事や、GitHubの公式プロジェクトの内容を元に、Sidekiq 7の新機能や変更点の解説を行います。

## 注意点

### 本記事で取り扱うエディション

本記事ではGitHubで[公開しているOSS版](https://github.com/mperham/sidekiq)のSidekiqについて記述しています。Pro / Enterprise版を使用している場合は、[公式サイト（英語）](https://sidekiq.org/)を参考にしてください。

### サポートされるRails / Ruby / Redisのバージョン

サポートされるバージョンは以下の通りになります。

* Ruby on Rails 6.0以上
* Ruby 2.7以上
* Redis 6.2以上

上記より古いバージョンを使用している場合は、アップグレードを事前に行う必要があります。

また、Redisとの接続で使用しているGemが`redis`から`redis-client`になったり、`redis-namespace`が削除されるなど、Sidekiqが依存するGemも変更になっているので、十分な動作確認を行う必要があります。

## 新機能

### 管理画面へのメトリクスの追加

ジョブの実行情報を詳細に表示するメトリクスが、Webの管理画面に追加されました。

以下の情報が、過去1時間のグラフとともに表示されます。

* Name: ジョブ名（Jobで終わるクラスの名前）
* Success: 成功ジョブ数（正常終了したジョブ数）
* Failure: 失敗ジョブ数（例外を発生して異常終了したジョブ数）
* Total Execution Time: 総実行時間（ジョブの実行時間の合計）
* Average Execution Time: 平均実行時間（1つのジョブあたり実行時間の平均）

![スクリーンショット 2023-03-07 18.52.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4358/43c15b67-0d9c-3d40-e677-90a63132b61e.png)

メトリクス自体は簡易的なもので、DataDogなどのフル機能のAPMを置き換えるものではないものの、Sidekiqだけである程度のジョブの実行時間などの情報を視覚的に知ることができるようになっています。

メトリクスの機能の詳細に関しては、以下の公式の記事を確認してください。

**参考**

Metrics · mperham/sidekiq Wiki
https://github.com/mperham/sidekiq/wiki/Metrics

### Pumaなどのプロセスへの埋め込み

これまでSidekiqは、PumaなどのWebサーバーとは別のプロセスと動いていましたが、Webサーバーのプロセス内で動かすことが可能になりました。

埋め込みの利点としては、デプロイが単純になる（設定を行なって、Webサーバーだけをデプロイすれば、Sidekiqも動く）ことと、メモリ消費が少なくなる（Webサーバー側でメモリに読み込んだRubyとRailsのコードやデータをSidekiq側でも使用できる）ことが挙げられます。

埋め込みの欠点としては、WebサーバーとSidekiqが1つのプロセスになっており、また、1つのCPUコアで1つのプロセスを実行することになるので、その中で同時に実行可能なスレッド数が限られていることが挙げられます。

上記の利点と欠点から、小規模なシステムの場合に向いている機能といえるでしょう。

実際にPumaにSidekiqを埋め込む場合は、以下のように設定を行います。（`config/sidekiq.yml`での設定はできません。）

```ruby
# config/puma.rb 
workers 2
threads 1, 3

require "sidekiq"
preload_app!

x = nil
on_worker_boot do
  x = Sidekiq.configure_embed do |config|
    config.queues = %w[default low]
    config.concurrency = 2
  end
  x.run
end

on_worker_shutdown do
  x&.stop
end
```

**参考**

Embedding · mperham/sidekiq Wiki
https://github.com/mperham/sidekiq/wiki/Embedding

### カプセル

ジョブをどのキューからいくつの同時実行数で実行するかを、カプセル（capsule）によって定義することができるようになりました。

以下の設定例では、`default`キューにあるジョブは同時実行数5、`low`キューにあるジョブは同時実行数3で実行します。これに加え、`unsafe`キューは同時実行数1にして、スレッド安全でないジョブを1スレッドで実行するようにしています。

```ruby
Sidekiq.configure_server do |config|
  # defaultカプセル
  config.queues = %w[default]
  config.concurrency = 5

  # lowカプセル
  config.capsule("low") do |cap|
    cap.queues = %w[low]
    cap.concurrency = 3
  end

  # unsafeカプセル
  config.capsule("unsafe") do |cap|
    cap.queues = %w[unsafe]
    cap.concurrency = 1
  end
end
```

参考

sidekiq/7.0-Upgrade.md at main · mperham/sidekiq
https://github.com/mperham/sidekiq/blob/main/docs/7.0-Upgrade.md

## 変更点

### Strict Argumentで、デフォルトでは例外を発生させるように

Sidekiqのバージョン6.4.0では、ジョブの引数が厳密なJSONになっていることを検証する、Strict Argumentが追加され、引数が不正な場合は警告を出力するようになっていましたが、Sidekiq 7ではこれが厳密化され、例外（`ArgumentError`）を発生するようになりました。

この挙動は`Sidekiq.strict_args!(false)`で無効にしたり、もしくは、`Sidekiq.strict_args!(:warn)`で元の警告の挙動に戻すことが可能です。

**参考**

Implement strict argument checking by kellysutton · Pull Request #5071 · mperham/sidekiq
https://github.com/mperham/sidekiq/pull/5071

### サーバー設定の記述方法の変更

Sidekiq 7では、内部的なAPIの実装のリファクタリングが行われた結果、以下の設定の記述方法の変更が行われています。

例: ロガーの設定

```ruby
# Sidekiq 6
Sidekiq.logger = ...

# Sidekiq 7
# Sidekiq.loggerは使用できなくなった
Sidekiq.configure_server do |cfg|
  cfg.logger = ...
end
```

例: コネクションプールの設定

```ruby
# Sidekiq 6
POOL1 = ConnectionPool.new(size: 5) { Redis.new(ENV['MY_REDIS_URL']) }
Sidekiq.configure_server do |cfg|
  cfg.redis = POOL1
end

# Sidekiq 7
# 直接ConnectionPoolのインスタンスを渡せなくなった
Sidekiq.configure_server do |cfg|
  cfg.redis = { url: ENV['MY_REDIS_URL'] }
end
```

**参考**

sidekiq/7.0-API-Migration.md at main · mperham/sidekiq
https://github.com/mperham/sidekiq/blob/main/docs/7.0-API-Migration.md

### redis-clientへの移行、redis-namespaceの削除

Sidekiqはこれまで`redis` Gemを使用していましたが、Sidekiq 7ではRedis 6.0以上のRESP3プロトコルを使用する`redis-client` Gemに移行しました。
Railsアプリケーションでは、`redis` Gemを引き続き使用できますが、`Sidekiq.redis`を使用したRedisとの接続を行う場合は、`redis-client`が使用されます。

また、`redis-namespace` Gemを使用したRedisのネームスペースのサポートが廃止されました。
この代わりに、Redisが標準で用意している0-15の数字で分けられたデータベースを使用することが推奨されています。

**参考**

sidekiq/7.0-Upgrade.md at main · mperham/sidekiq
https://github.com/mperham/sidekiq/blob/main/docs/7.0-Upgrade.md
Migrating from redis-namespace | Mike Perham
https://www.mikeperham.com/2017/04/10/migrating-from-redis-namespace/