5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

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

Last updated at Posted at 2021-09-14

この記事は

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 オプションでスーパバイザも生成します。

$ mix new redix_sample --sup

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

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

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

$ 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 します。

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 モジュールを読み込んで起動してみます。

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の強力な関数やパイプラインで自由にデータを成形できます!
例えばこんな感じでランキングを表示してみたり!

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 に追加してあげればよいです。

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に接続できるようになっていますね!
これで呼び出し時にコネクション生成しなくても気軽に呼べるようになりました!

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

5
4
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?