ElixirでRedisを操作するRedixの紹介！

# この記事は
9/16日開催の 
**Elixir Digitalization Implementors#7：推しライブラリをオススメ会** 
で発表する内容をまとめたものです。
https://fukuokaex.connpass.com/event/224883/

数年前からElxiir書いていますが、段々と使われるようになってきたなーという印象です。
お時間ある方はぜひ参加してみてください！

# Redix
Redix は Elixir で Redis を操作するライブラリです。おそらく一番メジャーなライブラリのはず？
https://github.com/whatyouhide/redix
https://hexdocs.pm/redix/Redix.html

## 使ってみる
プロジェクトを作ります。あとで使うので --sup オプションでスーパバイザも生成します。

```bash
$ mix new redix_sample --sup
```

次にredisを準備します。なんでもいいのですが、今回はローカルにdockerコンテナを立ててそこで実行することにします。

```yaml:docker-compose.yml
version: "3"
services:
  redis:
    image: "redis:latest"
    ports:
      - "6379:6379"
    volumes:
      - "./data/redis:/data"
```

動作確認。ランキングの実装でもよく使うZADDを使ってみたいと思います。
https://redis.io/commands/ZADD

```bash
$ docker-compose exec redis redis-cli
127.0.0.1:6379> ZADD my_ranking 10 test
(integer) 1
127.0.0.1:6379> ZADD my_ranking 20 test2
(integer) 1
127.0.0.1:6379> ZADD my_ranking 30 test3
(integer) 1
127.0.0.1:6379> ZRANGE my_ranking 0 -1 WITHSCORES
1) "test"
2) "10"
3) "test2"
4) "20"
5) "test3"
6) "30"
```

## Redixを使う
下記を追加して `mix deps.get` します。

```elixir:mix.exs
...
  defp deps do
    [
      # {:dep_from_hexpm, "~> 0.3.0"},
      # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
      {:redix, "~> 1.1"},
    ]
  end
...
```

`iex -S mix` で redix モジュールを読み込んで起動してみます。

```elixir
iex(1)> {:ok, conn} = Redix.start_link(host: "localhost", port: 6379)  
{:ok, #PID<0.353.0>}
iex(2)> conn |> Redix.command(["ZRANGE", "my_ranking", 0, -1, "WITHSCORES"])
{:ok, ["test", "10", "test2", "20", "test3", "30"]}
iex(3)> conn |> Redix.command(["ZADD", "my_ranking", 40, "test4_from_redix"])
{:ok, 1}
iex(4)> conn |> Redix.command(["ZRANGE", "my_ranking", 0, -1, "WITHSCORES"]) 
{:ok, ["test", "10", "test2", "20", "test3", "30", "test4_from_redix", "40"]}
```

ElixirからRedisが操作できていますね！
ここまでできればElixirの強力な関数やパイプラインで自由にデータを成形できます！
例えばこんな感じでランキングを表示してみたり！

```elixir
iex(5)> conn |> Redix.command!(["ZRANGE", "my_ranking", 0, -1, "WITHSCORES"]) |> Enum.chunk_every(2) |> Enum.with_index(1) |> Enum.map(fn {[name, score], rank} -> %{name: name, score: score, rank: rank} end)   
[
  %{name: "test", rank: 1, score: "10"},
  %{name: "test2", rank: 2, score: "20"},
  %{name: "test3", rank: 3, score: "30"},
  %{name: "test4_from_redix", rank: 4, score: "40"}
]
```

## コネクションをアプリケーション起動時に確立する
ここまでの方法だとRedisに接続する前に必ず `Redix.start_link` を呼んで、そのコネクションを保持しておく必要があります。
iexならいいのですが、実際にアプリケーション開発する時にはRedisに接続するたびにコネクションを確立するのはちょっと冗長だし、負荷的にもよろしくないですよね。
ということで、スーパバイザ起動時にRedixを起動するようにします。なおスーパバイザは --sup オプションで `mix new` した際に自動で生成されます。
具体的には `{Redix, host: "localhost", port: 6379, name: :redix}` を children に追加してあげればよいです。

```elixir:lib/redix_sample/application.ex
defmodule RedixSample.Application do
  @moduledoc false

  use Application

  @impl true
  def start(_type, _args) do
    children = [
      # 追加
      {Redix, host: "localhost", port: 6379, name: :redix}
    ]

    opts = [strategy: :one_for_one, name: RedixSample.Supervisor]
    Supervisor.start_link(children, opts)
  end
end
```

再度 `iex -S mix` をしてみると `:redix` という名前でRedisに接続できるようになっていますね！
これで呼び出し時にコネクション生成しなくても気軽に呼べるようになりました！

```elixir
iex(1)> Redix.command(:redix, ["ZRANGE", "my_ranking", 0, -1, "WITHSCORES"])
{:ok, ["test", "10", "test2", "20", "test3", "30", "test4_from_redix", "40"]}
```

ちなみに高負荷環境用にコネクションプール用意してをコネクションを使いまわすなどのテクもあるので、気になる方はドキュメント読んでみてください :thumbsup: 
https://hexdocs.pm/redix/real-world-usage.html#single-named-redix-instance

## Githubでコード確認できます
コードはgithubに置いているので参考にしてみてください。
https://github.com/koyo-miyamura/sandbox/tree/master/elixir/redix_sample