ConCacheの利用方法
※ はてなブログから引っ越しました(2019/10/21)
Elixir + PhoneixからREST APIを呼び出して取得したデータをConCacheを使ってキャッシュする方法を調べたので書いておく。
はじめに
まずは、mix.exsにcon_cacheを追加して、mix deps.getする。
defp deps do
[
{:con_cache, "~> 0.13"}, #この行を追加
]
end
applicaition.exのchildrenに以下を追加
children = [
...
{ConCache,
[name: :my_cache, ttl_check_interval: :timer.seconds(1), global_ttl: :timer.seconds(5)]},
...
]
名称 | 値サンプル | 説明 |
---|---|---|
name | :my_cache | ConCache管理するキャッシュ名 |
ttl_check_interval | :timer.seconds(1) | TTLチェック間隔 |
global_ttl | :timer.seconds(5) | キャッシュの有効期間 |
参照処理へ実装
元コードではREST APIを呼び出しているだけのControllerのコード
def index(conn, _params) do
users =
res = HTTPoison.get!("http://localhost:3000/users")
res.body
|> Poison.decode!()
render(conn, "index.html", users: users)
end
上のコードを次のように修正。ConCache.get_or_store
を使うことで、キャッシュにあればキャッシュを使用し、なければREST APIを呼び出している。
ConCache.get_or_store
の第1引数はキャッシュの名前、第2引数はキャッシュに登録するキー名、第3引数はキャッシュにない場合に実行される関数を指定する。
def index(conn, _params) do
users =
ConCache.get_or_store(:my_cache, :my_key, fn ->
res = HTTPoison.get!("http://localhost:3000/users")
res.body
|> Poison.decode!()
end)
render(conn, "index.html", users: users)
end
以上でTTLが有効な間はキャッシュが利用され、REST API呼び出しが無駄に増えることを避けることができる。
更新(新規作成)処理へ実装
このままだと、元データが更新されてもキャッシュが更新されるまでは古い情報が表示されるため、データ更新時にキャッシュも更新する。
createの中でREAT APIの更新処理が成功した場合にConCache.update_existing
を使ってキャッシュも更新している。ConCache.update_existing
はキャッシュに指定したキーがなければ追加、キーがあれば更新する。
第1引数と第2引数はConCache.get_or_store
と同じ。
第3引数の関数内でnew_value
に新しいキャッシュの内容を割り当て、{:ok, new_value}
を返せば良い。
この例では、キャッシュにあるユーザーの一覧に、新規ユーザーを追加している。
def create(conn, %{"user" => user_params}) do
changeset = User.changeset(%User{}, user_params)
req_body = user_params |> Poison.encode!()
case HTTPoison.post("http://localhost:3000/users", req_body, [
{"Content-Type", "application/json"}
]) do
{:ok, %HTTPoison.Response{status_code: 200}} ->
ConCache.update_existing(:my_cache, :my_key, fn old_value ->
new_value = old_value ++ [user_params]
{:ok, new_value}
end)
conn
|> put_flash(:info, "User created!")
|> redirect(to: Routes.user_path(conn, :index))
_ ->
conn
|> render("new.html", changeset: changeset)
end
ユーザー更新時はnewに同様の実装をする。