Livebook で Momento Cache

## はじめに

Momento Cache はサーバーレスキャッシュサービスです

https://jp.gomomento.com/

Lambda + DynamoDB というサーバーレスの黄金パターンに組み込んだ例があります

Momento にキャッシュがなければ DynamoDB を参照する、 Cache-Aside (キャッシュアサイド) パターンを実装した場合、レイテンシの 60 % を削減できる、としています

https://jp.gomomento.com/blog/oops-momento-ate-60-percent-of-my-lambda-latencies/

日本で Momento Cache を活用した事例としては、北海道テレビの事例などがあります

https://jp.gomomento.com/case-studies/htb/

先日参加した JAWS DAYS 2024 にて Momento の Elixir SDK があることを知ったので、 Livebook から使ってみます

https://qiita.com/RyoWakabayashi/items/2c8cbd8a92abc667c7e9

https://livebook.dev/

この記事ではキャッシュの作成、キーバリューの登録、取得を実装します

実装したノートブックはこちら

https://github.com/RyoWakabayashi/elixir-learning/blob/main/livebooks/momento/momento_cache.livemd

## 事前準備

### サインアップ

先に Momento のアカウントを用意しておきます

素晴らしいことに、試すだけであればクレジットカードの登録は不要です

以下のリンクから Momento にサインアップしましょう

https://jp.gomomento.com/

右上の「ログイン」をクリックします

![スクリーンショット 2024-03-10 8.37.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/b6198e67-73b2-3e96-aa4c-e7752c34359e.png)

メールアドレス、もしくは Google アカウントか GitHub アカウントでサインアップできます

![スクリーンショット 2024-03-10 8.37.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/7b1122b0-b4eb-7262-0247-919f42662185.png)

### API KEY の作成

サインアップできると、以下のような画面が表示されます

「Generate API Keys」をクリックしてください

![スクリーンショット 2024-03-10 8.38.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/5acc8e91-0638-4594-8253-8337ca0b343a.png)

API キーの作成画面が表示されます

試すだけならどこでも問題ありませんが、クラウドプロバイダーに AWS 、リージョンに ap-northeast-1 （東京）を選択します

「Type of key」は左側の「Super User Key」を選択します

下にある「トークンを生成する」ボタンをクリックしてください

![スクリーンショット 2024-03-10 8.43.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/b6e4fcfc-6de4-fbd1-6db7-7db285ed8e9a.png)

API Key が生成されます

後でこの値を使用します

![スクリーンショット 2024-03-10 8.43.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/053574a9-ba28-b5f6-0fd7-e1f32520af75.png)

## セットアップ

Livebook で新しいノートブックを開き、 Momento の SDK モジュールと Kino をインストールします

https://github.com/momentohq/client-sdk-elixir/tree/main

```elixir
Mix.install([
  {:gomomento, "~> 0.6"},
  {:kino, "~> 0.12"}
])
```

:::note warn
Hex の `momento` モジュールは JavaScript の日付時刻操作ライブラリである Moment.js を Elixir から使うためのものです

https://hex.pm/packages/momento

https://momentjs.com/

Momento を使うためのモジュールは `gomomento` なので気をつけましょう
:::

`Momento.CacheClient` は頻出するのでエイリアスを付けて `CacheClient` だけで使えるようにしておきます

```elixir
alias Momento.CacheClient
```

## クライアントの準備

Momento Cache を操作するためのクライアントを準備しましょう

先ほど取得した API キーを入力するための UI を作成します

```elixir
api_key_input = Kino.Input.password("API_KEY")
```

セルを実行するとパスワード型のテキスト入力が表示されるので、 API キーの値を入力します

![スクリーンショット 2024-03-11 0.19.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/cd9f059a-712b-bade-fb17-af2207293af2.png)

クライアントの設定を用意します

```elixir
config = Momento.Configurations.Laptop.latest()
```

実行結果
```elixir
%Momento.Config.Configuration{
  transport_strategy: %Momento.Config.Transport.TransportStrategy{
    grpc_config: %Momento.Config.Transport.GrpcConfiguration{deadline_millis: 5000}
  }
}
```

API キーの値を読み込んで認証情報プロバイダーを作成します

```elixir
credential_provider =
  api_key_input
  |> Kino.Input.read()
  |> Momento.Auth.CredentialProvider.from_string!()
```

設定情報、認証情報プロバイダー、TTL（キーバリューを残しておく秒数）を指定してクライアントを作成します

```elixir
default_ttl_seconds = 60.0
client = CacheClient.create!(config, credential_provider, default_ttl_seconds)
```

## キャッシュの作成

キャッシュ名を設定します

```elixir
cache_name = "cache"
```

クライアントとキャッシュ名を指定してキャッシュを作成します

```elixir
CacheClient.create_cache(client, cache_name)
```

実行結果
```elixir
{:ok, %Momento.Responses.CreateCache.Ok{}}
```

キャッシュの一覧を取得してみます

```elixir
CacheClient.list_caches(client)
```

実行結果
```elixir
{:ok, %Momento.Responses.ListCaches.Ok{caches: [%Momento.Responses.CacheInfo{name: "cache"}]}}
```

Momento のコンソールの方からも確認してみます

https://console.gomomento.com/caches

確かに指定した名前でキャッシュが作成されています

![スクリーンショット 2024-03-10 8.55.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/d895838b-007a-dbff-6879-4417b6be9d37.png)

ちなみに、すでに存在している名前でキャッシュを作成しようとすると、以下のような結果になります

```elixir
:already_exists
```

## キーバリューの登録、取得

キャッシュ、キー、バリューを指定して登録します

```elixir
CacheClient.set(client, cache_name, "foo", "bar")
```

実行結果
```elixir
{:ok, %Momento.Responses.Set.Ok{}}
```

キャッシュ、キーを指定して取得します

```elixir
CacheClient.get(client, cache_name, "foo")
```

実行結果
```elixir
{:ok, %Momento.Responses.Get.Hit{value: "bar"}}
```

Momento のコンソールでも確認できます

![スクリーンショット 2024-03-10 8.56.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/25e6c2b0-9c10-b551-9488-fdce2ec4d86d.png)

TTLが60秒なので、 60 秒以上経過してからもう一度値を取得すると、実行結果は以下のようになります

```elixir
:miss
```

こうなった場合、キャッシュではなく元のデータベースを参照しに行くことになります

## まとめ

Elixir 用の SDK を使うことで、 Livebook から簡単に Momento Cache を試すことができました

キャッシュが必要なパターンが出てきたときに是非活用したいですね