今回やること
Upstash Redisへ接続し、文字列を保存・取得して、期限付きcacheを動かします。
到達点は次のとおりです。
- REST URLとtokenを環境変数へ保存する
@upstash/redisのRedis.fromEnv()で接続するsetとgetを実行する- TTL付きcacheの失効を確認する
REST tokenはserver側だけで使い、browserやrepositoryへ公開しません。
Upstash Redisとは
Upstash RedisはHTTP/REST経由で利用できるRedis serviceです。connectionを長時間維持しにくいserverless functionやedge環境でも使いやすいclientが提供されています。
この記事では多機能なsession、ranking、Pub/Subには広げず、cacheの基本だけを扱います。
前提条件
- Node.js 20.6以上を利用できる
- Upstash accountがある
- Redis databaseを作成済み
node --version
- database details画面を確認できる
本番dataではなく、削除してよい学習用databaseを使ってください。
プロジェクトを準備する
空のfolderでpackageを初期化し、公式TypeScript/JavaScript clientをinstallします。
npm init -y
npm install @upstash/redis
package.jsonを次のようにします。
{
"type": "module",
"scripts": {
"redis:test": "node redis-cache.mjs"
}
}
npm install @upstash/redisが追加したversionとlockfileを使います。
環境変数を設定する
Upstash consoleのdatabase detailsからREST URLとREST tokenを確認します。
.envへ保存します。
UPSTASH_REDIS_REST_URL=https://your-database.upstash.io
UPSTASH_REDIS_REST_TOKEN=your-secret-token
.envはcommitしません。
.env
.env.local
値をscreen shot、質問文、error reportへ貼らないでください。漏えいしたtokenは無効化して再発行します。
Redis clientを初期化する
project rootへredis-cache.mjsを作ります。
import { Redis } from "@upstash/redis";
const redis = Redis.fromEnv();
const key = "practice:greeting";
await redis.set(key, "hello");
const value = await redis.get(key);
console.log({ key, value });
Redis.fromEnv()は次の2変数を読みます。
UPSTASH_REDIS_REST_URLUPSTASH_REDIS_REST_TOKEN
独自名を使う場合はnew Redis({ url, token })で明示しますが、この記事では公式の環境変数名へ統一します。
保存と取得を実行する
Node.js 20.6以上なら--env-fileで.envを読み込めます。
node --env-file=.env redis-cache.mjs
成功すると次のように表示されます。
{ key: 'practice:greeting', value: 'hello' }
文字列を保存しても、getの返り値の型は利用するdataに合わせて確認してください。存在しないkeyではnullになります。
TTL付きcacheを作る
cacheは永遠に残さず、有効期限を決めます。先ほどのcodeを次へ置き換えます。
import { Redis } from "@upstash/redis";
const redis = Redis.fromEnv();
const key = "practice:profile:42";
await redis.set(
key,
{ name: "Ada", course: "Web" },
{ ex: 10 },
);
const cached = await redis.get(key);
const ttl = await redis.ttl(key);
console.log({ cached, ttl });
ex: 10は10秒後にkeyを失効させる指定です。実際のTTLはdata更新頻度と、古い値を許容できる時間から決めます。
cache missを扱う
cacheに値がない場合だけ、元dataを取得して保存します。
async function getProfile(userId) {
const key = `profile:${userId}`;
const cached = await redis.get(key);
if (cached !== null) {
return { source: "cache", profile: cached };
}
const profile = await loadProfileFromDatabase(userId);
await redis.set(key, profile, { ex: 60 });
return { source: "database", profile };
}
この形はcache-asideと呼ばれます。database更新時は、該当keyを削除するか更新し、古いdataが残らないようにします。
key名を設計する
異なる用途のkeyが衝突しないよう、prefixを付けます。
practice:profile:42
practice:article:100
production:profile:42
環境、data種類、IDの順に揃えると調査しやすくなります。
email addressやtokenをそのままkeyへ含めないでください。個人情報を保存する場合は、保存目的と保持期間も確認します。
成功を確認する
次の順に確認します。
set後のgetで同じ値を取得できるttlが正の秒数を返す- 期限後の
getがnullになる - consoleやGit差分へtokenが出ていない
確認後は学習用keyを削除できます。
await redis.del("practice:greeting");
await redis.del("practice:profile:42");
よくあるつまずき
環境変数名が違う
Redis.fromEnv()では公式名のUPSTASH_REDIS_REST_URLとUPSTASH_REDIS_REST_TOKENを使います。
tokenをclient componentへ渡す
browser bundleへ含めません。Redis accessはserver側のrouteやfunctionで実行します。
TTLを付け忘れる
cache用途なら期限を決めます。永続dataの保存先として無計画に使いません。
nullを通常dataとして扱う
cache missを分岐し、元dataの取得へ進みます。
練習
記事titleを30秒cacheする処理を考えてください。
確認基準は次のとおりです。
- keyは
practice:article:100 - cache hitならdatabaseを読まない
- cache missならdatabaseから読み、
ex: 30で保存する - 30秒後は再びcache missになる
- tokenをlogへ出さない
まとめ
@upstash/redisをinstallする- 公式環境変数名を
.envへ保存する Redis.fromEnv()でserver側から接続するset、get、ttl、delを確認する- cacheには用途に合うTTLを付ける
次のステップ
基本cacheを確認した後に、rate limitやsessionなど、別のdata要件を個別に学びましょう。