この記事は
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コンテナを立ててそこで実行することにします。
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
します。
...
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 に追加してあげればよいです。
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"]}
ちなみに高負荷環境用にコネクションプール用意してをコネクションを使いまわすなどのテクもあるので、気になる方はドキュメント読んでみてください
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