Skip to main content

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_cacheConCache管理するキャッシュ名
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に同様の実装をする。