cache-manager
GitHub概要
jaredwray/cacheable
a robust, scalable, and maintained set of caching packages
スター1,891
ウォッチ10
フォーク200
作成日:2013年4月6日
言語:TypeScript
ライセンス:MIT License
トピックス
cachecachingcaching-libraryhttpkey-valuekeyvnodejsredisrfc-72wrapper
スター履歴
データ取得日時: 2025/10/22 09:55
ライブラリ
cache-manager
概要
cache-managerは、Node.js用のキャッシュモジュールで、複数のキャッシュストアを統一インターフェースで管理できるマルチストアキャッシュマネージャーです。TypeScript対応で、階層化されたキャッシュアーキテクチャを簡単に構築できます。
詳細
cache-manager(キャッシュマネージャー)は、関数を簡単にキャッシュでラップし、階層キャッシュとプラグインアーキテクチャによる一貫したインターフェースを提供するNode.jsキャッシュライブラリです。TypeScriptで作成され、ESModulesと互換性があり、バージョン7.0.0が最新リリースです。バックグラウンドでの期限切れキャッシュキー更新メカニズムを提供し、Redis、MongoDB、データベース、ファイルシステムなど多様なストレージでコンテンツをキャッシュできます。マルチキャッシュ機能により、レベル1(メモリ)とレベル2(Redis)といったキャッシュ階層ラッパーを作成し、複数ストア使用時には最初に見つかった(最速の)値を返すか、すべてのストアの完了を待たずに動作する非ブロッキングモードの設定が可能です。NestJSや他のフレームワークでの採用実績があり、npmレジストリで1404以上のプロジェクトで使用されています。
メリット・デメリット
メリット
- 統一インターフェース: 複数のキャッシュストアを一貫したAPIで操作
- TypeScript完全対応: 型安全性と優れた開発体験
- マルチストア対応: 階層化されたキャッシュアーキテクチャの構築
- 豊富なドライバー: Redis、MongoDB、ファイルシステム等幅広いサポート
- フレームワーク統合: NestJS等での実績とサポート
- 非ブロッキングモード: 高速レスポンス時間の実現
- プラグインアーキテクチャ: 拡張性と柔軟性の確保
デメリット
- 複雑性: 単純なキャッシュ需要には機能が過剰
- パフォーマンスオーバーヘッド: 抽象化レイヤーによる若干の性能低下
- 設定の複雑さ: マルチストア設定時の構成管理が複雑
- 依存関係: 使用するドライバーに応じた追加パッケージが必要
- 学習コスト: 高度な機能活用には概念理解が必要
主要リンク
書き方の例
基本的なインメモリキャッシュ
import { createCache } from 'cache-manager'
// インメモリストア作成
const memoryCache = createCache({
store: 'memory',
max: 100, // 最大アイテム数
ttl: 60000 // TTL (ミリ秒)
})
// 値を設定
await memoryCache.set('key', 'value', 30000) // 30秒TTL
// 値を取得
const value = await memoryCache.get('key')
console.log(value) // 'value'
// 値を削除
await memoryCache.del('key')
// キャッシュクリア
await memoryCache.reset()
マルチストア設定(階層キャッシュ)
import { createCache } from 'cache-manager'
import { createKeyv } from 'cacheable'
import { createKeyv as createKeyvRedis } from '@keyv/redis'
// 複数ストアの設定
const memoryStore = createKeyv() // L1: メモリ
const redisStore = createKeyvRedis('redis://user:pass@localhost:6379') // L2: Redis
const cache = createCache({
stores: [memoryStore, redisStore]
})
// 階層キャッシュの使用
await cache.set('user:123', { name: 'John', age: 30 })
// 最初に見つかった値を返す(通常はメモリから)
const user = await cache.get('user:123')
console.log(user)
wrap関数による自動キャッシュ
import { createCache } from 'cache-manager'
const cache = createCache({
store: 'memory',
ttl: 60000
})
// データベースアクセス関数をキャッシュでラップ
async function getUserFromDb(userId) {
console.log('データベースから取得中...')
// 実際のDB処理をシミュレート
await new Promise(resolve => setTimeout(resolve, 100))
return { id: userId, name: `User${userId}`, email: `user${userId}@example.com` }
}
// wrap関数でキャッシュ機能付きに
async function getUser(userId) {
return await cache.wrap(`user:${userId}`, () => getUserFromDb(userId))
}
// 初回はDBから取得、2回目以降はキャッシュから
const user1 = await getUser('123') // DB アクセス
const user2 = await getUser('123') // キャッシュから取得
Redis統合
import { createCache } from 'cache-manager'
import { createRedisStore } from 'cache-manager-redis-store'
const redisCache = createCache({
store: createRedisStore({
host: 'localhost',
port: 6379,
password: 'your-password',
db: 0
}),
ttl: 600 // 10分
})
// Redisキャッシュの使用
await redisCache.set('session:abc123', {
userId: '456',
loginTime: new Date().toISOString()
}, 3600000) // 1時間
const session = await redisCache.get('session:abc123')
TypeScript型安全な使用
import { createCache, Cache } from 'cache-manager'
interface User {
id: string
name: string
email: string
}
interface CacheConfig {
userCache: Cache
sessionCache: Cache
}
class UserService {
private caches: CacheConfig
constructor() {
this.caches = {
userCache: createCache({
store: 'memory',
max: 1000,
ttl: 300000 // 5分
}),
sessionCache: createCache({
store: 'memory',
max: 10000,
ttl: 1800000 // 30分
})
}
}
async getUser(userId: string): Promise<User | null> {
const cacheKey = `user:${userId}`
// キャッシュから取得試行
let user = await this.caches.userCache.get<User>(cacheKey)
if (!user) {
// DBから取得
user = await this.fetchUserFromDatabase(userId)
if (user) {
await this.caches.userCache.set(cacheKey, user)
}
}
return user
}
private async fetchUserFromDatabase(userId: string): Promise<User | null> {
// データベースアクセスの実装
return {
id: userId,
name: `User ${userId}`,
email: `user${userId}@example.com`
}
}
}
マルチストア非ブロッキングモード
import { createCache } from 'cache-manager'
import { createKeyv } from 'cacheable'
import { createKeyv as createKeyvRedis } from '@keyv/redis'
const memoryStore = createKeyv()
const redisStore = createKeyvRedis('redis://localhost:6379')
const cache = createCache({
stores: [memoryStore, redisStore],
nonBlocking: true // 非ブロッキングモード
})
// 非ブロッキングモードでは
// set/mset - すべてのストアの完了を待たない
// get/mget - 最初に見つかった値を即座に返す
// del/mdel - すべてのストアの完了を待たない
await cache.set('fast-key', 'fast-value') // すぐに完了
const value = await cache.get('fast-key') // 最速ストアから取得
カスタムストアの実装
class CustomMemoryStore {
constructor() {
this.cache = new Map()
this.timers = new Map()
}
async get(key) {
return this.cache.get(key)
}
async set(key, value, ttl) {
this.cache.set(key, value)
if (ttl) {
// 既存タイマーをクリア
if (this.timers.has(key)) {
clearTimeout(this.timers.get(key))
}
// 新しいタイマーを設定
const timer = setTimeout(() => {
this.cache.delete(key)
this.timers.delete(key)
}, ttl)
this.timers.set(key, timer)
}
}
async del(key) {
if (this.timers.has(key)) {
clearTimeout(this.timers.get(key))
this.timers.delete(key)
}
this.cache.delete(key)
}
async reset() {
this.timers.forEach(timer => clearTimeout(timer))
this.cache.clear()
this.timers.clear()
}
}
// カスタムストアの使用
const customCache = createCache({
store: new CustomMemoryStore()
})