メインコンテンツまでスキップ

Redis KV Driver

@zeltjs/kv@zeltjs/kv/adaptor-redis エントリポイント経由で Redis バックエンドを提供します。RedisKVAdaptorioredis を用いて AtomicKVAdaptor を実装し、incrsetnx などのアトミック操作をサポートします。

インストール

pnpm add @zeltjs/kv @zeltjs/redis

peer dependency:

pnpm add @zeltjs/core

基本的なセットアップ

RedisKVAdaptor を inject し、namespace 化したストアを作成します。namespace()AtomicKVStore をそのまま返し、get() は値(キーが存在しない場合は undefined)に解決されます。unwrap が必要な result ラッパーはありません:

@Injectable()
export class CacheService {
  private store: AtomicKVStore;

  constructor(kv = inject(RedisKVAdaptor)) {
    this.store = kv.namespace('cache:');
  }

  async get<T>(key: string): Promise<T | undefined> {
    return this.store.get<T>(key);
  }

  async set<T extends Defined>(key: string, value: T, ttlSec?: number): Promise<void> {
    await this.store.set(key, value, { ttlSec });
  }
}

アプリ生成時に RedisConfigRedisKVAdaptor を登録します。RedisConfig が接続設定を提供し(RedisKVAdaptor が依存する RedisService が利用します)、依存は自動的に解決されるため、injectables には RedisKVAdaptor を挙げるだけで十分です:

const app = createApp([http({
    controllers: [AppController],
  })], { configs: [RedisConfig] });

デフォルトでは、RedisConfig は接続 URL を環境変数 REDIS_URL から読み取り、未設定時は redis://localhost:6379 にフォールバックします。

カスタム設定

RedisConfig を継承して接続設定をカスタマイズできます。options getter は ioredis の RedisOptions を返します:

@Config
class CustomRedisConfig extends RedisConfig {
  override get url(): string {
    return this.env.getString('REDIS_URL', 'redis://localhost:6379');
  }

  override get options() {
    return {
      maxRetriesPerRequest: 3,
      retryStrategy: (times: number) => Math.min(times * 100, 3000),
    };
  }
}

デフォルトの代わりにカスタム config を登録します:

const app = createApp([http({
    controllers: [AppController],
  })], { configs: [CustomRedisConfig] });

API リファレンス

RedisKVAdaptor

メソッド説明
namespace(prefix)namespace 化された AtomicKVStore を返す

RedisKVAdaptor はアプリケーションのライフサイクルに参加します。ioredis の接続は RedisService が保持し、シャットダウン時に自動的に切断されます(グレースフルシャットダウンを参照)。

AtomicKVStore のメソッド

メソッド説明
get<T>(key)値を取得(存在しない場合は undefined
set<T>(key, value, opts?)TTL 任意指定で値を保存
del(key)キーを削除
has(key)キーの存在確認
expire(key, ttlSec)既存キーの TTL を更新
incr(key, by?, opts?)アトミックなインクリメント
setnx<T>(key, value, opts?)存在しない場合のみ set
namespace(prefix)ネストした namespace を作成

本番環境のセットアップ

本番デプロイでは、接続プールとリトライ動作を設定します:

@Config
class ProductionRedisConfig extends RedisConfig {
  override get options() {
    return {
      maxRetriesPerRequest: 3,
      enableReadyCheck: true,
      retryStrategy: (times: number) => {
        if (times > 10) return null;
        return Math.min(times * 200, 5000);
      },
    };
  }
}

グレースフルシャットダウン

Redis を手動で切断する必要はありません。RedisService がライフサイクルマネージャに自身を登録するため、アプリケーションのシャットダウン時に ioredis クライアントが自動的に切断されます。

@zeltjs/adapter-node を使う場合、onNodeSIGINT/SIGTERM ハンドラを登録してこのシャットダウンをトリガーします。handle.shutdown() でも同様です:

const handle = await nodeApp.listen({ port: 3000 });

// サーバを停止し、ライフサイクルのシャットダウン(Redis を含む)を実行
await handle.shutdown();