🪂

TypeScript x Momento | Node.js SDK でキャッシュを操作する

2024/05/22に公開

Momento Cache

今、勢いのあるサーバーレスのキャッシュサービスで、圧倒的な高速性と使いやすさが売りです。

https://jp.gomomento.com/services/momento-cache/

Momento Cacheは、世界初の真のサーバーレスキャッシングサービスです。瞬時の弾力性、scale-to-zero機能、圧倒的な高速パフォーマンスを提供します。 容量の選択、管理、プロビジョニングが必要な時代は終わりました。Momento Cacheでは、SDKを入手し、エンドポイントを取得し、コードに数行入力するだけで、すぐに実行できます。

Momento Cache Documentation | Momento Docs

コンソールにログインして、すぐにキャッシュを扱うことができます。

本当にシンプルで簡単にサーバーレスの恩恵を受けることができます🙌

client-sdk-javascript

Node.js 用の SDK があるので、
TypeScript で Momento Cache を扱うサンプルコードを実装してみたいと思います。

https://www.npmjs.com/package/@gomomento/sdk

Node.js SDK でキャッシュを操作する

キャッシュの作成

Momento コンソール にログインして、キャッシュを作成します。

キャッシュの作成

また、API キーページ で API キーを発行します。

セットアップ

サンドボックス用のプロジェクトを作成します。

mkdir momento-node-sandbox
cd momento-node-sandbox
npm init -y
npm i -D typescript tsx
npx tsc --init
touch index.ts
echo "MOMENTO_API_KEY=" > .env

.env ファイルを扱うために @dotenvx/dotenvx もインストールします。

npm i @dotenvx/dotenvx
npm i @gomomento/sdk

MOMENTO_API_KEY に API キーを定義しておきます。

文字列の Set と Get

基本であろう、文字列の Set と Get を確認します。

index.ts
import { CacheClient, CacheGet, Configurations, CredentialProvider } from "@gomomento/sdk";

const CACHE_NAME = 'momento-sandbox';

// キャッシュクライアントの生成
const genClient = async () => {
    return await CacheClient.create({
            configuration: Configurations.Laptop.v1(),
            credentialProvider: CredentialProvider.fromEnvironmentVariable({
            environmentVariableName: 'MOMENTO_API_KEY',
        }),
        defaultTtlSeconds: 300,
    });
};

console.log('Set and Get...');
genClient().then(async (client) => {
    // キャッシュをセットする
    await client.set(CACHE_NAME, 'my_key', 'hello, world!!!!');

    // キャッシュを取得する
    const result = await client.get(CACHE_NAME, 'my_key');

    if (result instanceof CacheGet.Hit) {
        console.log(result);
        console.log(result.valueString());
    } else if (result instanceof CacheGet.Miss) {
        console.log(result);
    } else if (result instanceof CacheGet.Error) {
        console.error(result);
    }

    // キャッシュを削除する
    await client.delete(CACHE_NAME, 'my_list_key');
}).catch((error) => {
    console.error(error);
});

以下のコマンドを実行して、テストします!

% npx dotenvx run -- npx tsx index.ts
[dotenvx@0.43.2] injecting env (1) from .env
Set and Get...
Hit {
  body: Uint8Array(11) [
     72, 101, 108, 108,
    111,  95, 119, 111,
    114, 108, 100
  ]
}
Hello_world

無事に取得できました👏👏👏

defaultTtlSeconds を指定しているので、キャッシュデータの TTL は 300 秒です。

valueString メソッドを使うことで、データをバイト配列からデコードした utf-8 文字列で返してくれます。

また、 CacheGet.Miss は TTL を超過してデータを取得できない場合も含まれるので、エラーとして処理しない方が望ましいでしょう。

Lists(配列)の操作

配列の連結

配列の末尾もしくは先頭に配列を連結することができます。

  • ListConcatenateBack:末尾に要素を追加する
  • ListConcatenateFront:先頭に要素を追加する
index.ts
console.log('Lists...');
genClient().then(async (client) => {
    // 配列をセットする
    await client.listConcatenateBack(CACHE_NAME, 'my_list_key', ["a", "b", "c"]);

    // 末尾に配列を連結する
    await client.listConcatenateBack(CACHE_NAME, 'my_list_key', ["d", "e", "f"]);

    // 先頭に配列を連結する
    await client.listConcatenateFront(CACHE_NAME, 'my_list_key', ["g", "h", "i"]);

    // キャッシュを取得する
    const result = await client.listFetch(CACHE_NAME, 'my_list_key');

    if (result instanceof CacheListFetch.Hit) {
        console.log(result);
        console.log(result.valueListString());
    } else if (result instanceof CacheListFetch.Miss) {
        console.log(result);
    } else if (result instanceof CacheListFetch.Error) {
        console.error(result);
    }

    // キャッシュを削除する
    await client.delete(CACHE_NAME, 'my_list_key');
}).catch((error) => {
    console.error(error);
});

実行結果です。

% npx dotenvx run -- npx tsx index.ts
[dotenvx@0.43.2] injecting env (1) from .env
Lists...
Hit {
  _values: [
    Uint8Array(1) [ 103 ],
    Uint8Array(1) [ 104 ],
    Uint8Array(1) [ 105 ],
    Uint8Array(1) [ 97 ],
    Uint8Array(1) [ 98 ],
    Uint8Array(1) [ 99 ],
    Uint8Array(1) [ 100 ],
    Uint8Array(1) [ 101 ],
    Uint8Array(1) [ 102 ]
  ]
}
[
  'g', 'h', 'i',
  'a', 'b', 'c',
  'd', 'e', 'f'
]

配列の要素の削除

配列の末尾もしくは先頭の要素を削除することができます。

  • ListPopBack:末尾に要素を削除する
  • ListPopFront:先頭に要素を削除する
index.ts
console.log('Lists...');
genClient().then(async (client) => {
    // 配列をセットする
    await client.listConcatenateBack(CACHE_NAME, 'my_list_key', ["a", "b", "c"]);

    // 末尾に要素を削除する
    const listPopBackResult = await client.listPopBack(CACHE_NAME, 'my_list_key');
    if (listPopBackResult instanceof CacheListPopBack.Hit) {
        console.log(listPopBackResult);
        console.log(`Removed value: ${listPopBackResult.valueString()}`);
    }

    // 先頭に要素を削除する
    const listPopFrontResult = await client.listPopFront(CACHE_NAME, 'my_list_key');
    if (listPopFrontResult instanceof CacheListPopFront.Hit) {
        console.log(listPopFrontResult);
        console.log(`Removed value: ${listPopFrontResult.valueString()}`);
    }

    // キャッシュを取得する
    const result = await client.listFetch(CACHE_NAME, 'my_list_key');

    if (result instanceof CacheListFetch.Hit) {
        console.log(result);
        console.log(result.valueListString());
    } else if (result instanceof CacheListFetch.Miss) {
        console.log(result);
    } else if (result instanceof CacheListFetch.Error) {
        console.error(result);
    }

    // キャッシュを削除する
    await client.delete(CACHE_NAME, 'my_list_key');
}).catch((error) => {
    console.error(error);
});

実行結果です。

listPopBacklistPopFront は、返り値に削除された要素を持っています。

% npx dotenvx run -- npx tsx index.ts
[dotenvx@0.43.2] injecting env (1) from .env
Lists...
Hit { body: Uint8Array(1) [ 99 ] }
Removed value: c
Hit { body: Uint8Array(1) [ 97 ] }
Removed value: a
Hit { _values: [ Uint8Array(1) [ 98 ] ] }
[ 'b' ]

配列に要素を追加する

配列に要素を追加することができます。

  • ListPushBack:末尾に要素を追加する
  • ListPushFront:先頭に要素を追加する

ListConcatenateBack や ListConcatenateFront との違いは、追加する対象が配列か単一の要素かです。

index.ts
console.log('Lists...');
genClient().then(async (client) => {
    // 配列をセットする
    await client.listConcatenateBack(CACHE_NAME, 'my_list_key', ["a", "b", "c"]);

    // 末尾に要素を追加する
    const listPopBackResult = await client.listPushBack(CACHE_NAME, 'my_list_key', "d");
    if (listPopBackResult instanceof CacheListPushBack.Success) {
        console.log(listPopBackResult);
        console.log(`List length: ${listPopBackResult.listLength()}`);
    }

    // 先頭に要素を追加する
    const listPopFrontResult = await client.listPushFront(CACHE_NAME, 'my_list_key', "e");
    if (listPopFrontResult instanceof CacheListPushFront.Success) {
        console.log(listPopFrontResult);
        console.log(`List length: ${listPopFrontResult.listLength()}`);
    }

    // キャッシュを取得する
    const result = await client.listFetch(CACHE_NAME, 'my_list_key');

    if (result instanceof CacheListFetch.Hit) {
        console.log(result);
        console.log(result.valueListString());
    } else if (result instanceof CacheListFetch.Miss) {
        console.log(result);
    } else if (result instanceof CacheListFetch.Error) {
        console.error(result);
    }

    // キャッシュを削除する
    await client.delete(CACHE_NAME, 'my_list_key');
}).catch((error) => {
    console.error(error);
});

実行結果です。

listPushBacklistPushFront は、返り値に追加後の配列の長さを持っています。

% npx dotenvx run -- npx tsx index.ts
[dotenvx@0.43.2] injecting env (1) from .env
Lists...
Success { _list_length: 4, is_success: true }
List length: 4
Success { _list_length: 5, is_success: true }
List length: 5
Hit {
  _values: [
    Uint8Array(1) [ 101 ],
    Uint8Array(1) [ 97 ],
    Uint8Array(1) [ 98 ],
    Uint8Array(1) [ 99 ],
    Uint8Array(1) [ 100 ]
  ]
}
[ 'e', 'a', 'b', 'c', 'd' ]

指定した要素を削除する

指定した要素を削除することができます。

  • ListRemoveValue:指定した要素を削除する
index.ts
console.log('Lists...');
genClient().then(async (client) => {
    // 配列をセットする
    await client.listConcatenateBack(CACHE_NAME, 'my_list_key', ["a", "b", "c"]);

    // 指定した要素を削除する
    const listPopBackResult = await client.listRemoveValue(CACHE_NAME, 'my_list_key', "b");
    if (listPopBackResult instanceof CacheListRemoveValue.Success) {
        console.log(listPopBackResult);
        console.log(`isSuccess: ${listPopBackResult.is_success}`);
    }

    // キャッシュを取得する
    const result = await client.listFetch(CACHE_NAME, 'my_list_key');

    if (result instanceof CacheListFetch.Hit) {
        console.log(result);
        console.log(result.valueListString());
    } else if (result instanceof CacheListFetch.Miss) {
        console.log(result);
    } else if (result instanceof CacheListFetch.Error) {
        console.error(result);
    }

    // キャッシュを削除する
    await client.delete(CACHE_NAME, 'my_list_key');
}).catch((error) => {
    console.error(error);
});

実行結果です。

% npx dotenvx run -- npx tsx index.ts
[dotenvx@0.43.2] injecting env (1) from .env
Lists...
Success { is_success: true }
isSuccess: true
Hit { _values: [ Uint8Array(1) [ 97 ], Uint8Array(1) [ 99 ] ] }
[ 'a', 'c' ]

まとめ

今回は Momento Cache でシンプルな文字列と配列をキャッシュするサンプルコードを書いてみました。

他にも、辞書型や Sorted sets という型も扱えます。

Sorted setsは、値(文字列)とスコア(符号付きダブル64ビットフロート)のペアを持つユニークな要素のコレクションです。項目の要素はスコア値順に並べられます。

Supported data types | Momento Docs

気になる方は、ぜひ触ってみてください🔥

今回のソースコードは Github にも置いてあります。

https://github.com/codemountains/momento-node-sandbox

参考

コラボスタイル Developers

Discussion