Redis Client
Redis client for caching and rate limiting
Redis Client
The @entro314labs/redis-client package provides a Redis client for caching, rate limiting, and session management in Entrolytics.
Installation
pnpm add @entro314labs/redis-clientnpm install @entro314labs/redis-clientyarn add @entro314labs/redis-clientbun add @entro314labs/redis-clientQuick Start
import { RedisClient } from '@entro314labs/redis-client'
const redis = new RedisClient({
url: process.env.REDIS_URL,
})
await redis.connect()
// Basic operations
await redis.set('key', { data: 'value' })
const data = await redis.get('key')
// Rate limiting
const exceeded = await redis.rateLimit('api:user:123', 100, 60)Configuration
import { RedisClient } from '@entro314labs/redis-client'
const redis = new RedisClient({
// Required
url: process.env.REDIS_URL,
// Optional
prefix: 'entrolytics:',
defaultTTL: 3600,
connectTimeout: 10000,
commandTimeout: 5000,
lazyConnect: true,
})Configuration Options
| Option | Type | Default | Description |
|---|---|---|---|
url | string | - | Redis connection URL (required) |
prefix | string | 'entrolytics:' | Key prefix for all operations |
defaultTTL | number | 3600 | Default TTL in seconds |
connectTimeout | number | 10000 | Connection timeout (ms) |
commandTimeout | number | 5000 | Command timeout (ms) |
lazyConnect | boolean | true | Connect on first operation |
API Reference
Connection
connect()
Establish Redis connection.
await redis.connect()disconnect()
Close Redis connection.
await redis.disconnect()healthCheck()
Check connection health with latency.
const { connected, latency } = await redis.healthCheck()
console.log(`Connected: ${connected}, Latency: ${latency}ms`)Basic Operations
get(key)
Get a value (JSON parsed automatically).
const user = await redis.get<User>('user:123')set(key, value, ttl?)
Set a value with optional TTL.
// With default TTL
await redis.set('user:123', { name: 'John' })
// With custom TTL (seconds)
await redis.set('session:abc', { userId: '123' }, 3600)
// With TTL options
await redis.set('cache:data', data, { ex: 3600 }) // seconds
await redis.set('cache:data', data, { px: 60000 }) // milliseconds
await redis.set('cache:data', data, { exat: 1735689600 }) // unix timestampdel(key)
Delete a key.
await redis.del('user:123')exists(key)
Check if key exists.
const exists = await redis.exists('user:123')Numeric Operations
incr(key)
Increment a value.
const newValue = await redis.incr('counter')decr(key)
Decrement a value.
const newValue = await redis.decr('counter')TTL Operations
expire(key, seconds)
Set TTL on existing key.
await redis.expire('session:abc', 3600)ttl(key)
Get remaining TTL.
const remaining = await redis.ttl('session:abc')Rate Limiting
rateLimit(key, limit, window)
Check rate limit (returns true if exceeded).
// 100 requests per 60 seconds
const exceeded = await redis.rateLimit('api:user:123', 100, 60)
if (exceeded) {
return new Response('Too Many Requests', { status: 429 })
}getRemainingRequests(key, limit, window)
Get remaining requests in window.
const remaining = await redis.getRemainingRequests('api:user:123', 100, 60)
console.log(`Remaining requests: ${remaining}`)Cache Patterns
fetch(key, fetcher, ttl?)
Cache-through pattern: get from cache or fetch and cache.
const user = await redis.fetch(
'user:123',
async () => await db.query.user.findFirst({ where: eq(user.id, '123') }),
3600
)store(key, value, ttl?)
Store value in cache (alias for set).
await redis.store('user:123', userData, 3600)invalidate(key)
Remove from cache (soft delete).
await redis.invalidate('user:123')invalidatePattern(pattern)
Delete all keys matching pattern.
// Delete all user cache entries
await redis.invalidatePattern('user:*')
// Delete all cache for a website
await redis.invalidatePattern('website:abc:*')Statistics
getStats()
Get cache hit/miss statistics.
const stats = redis.getStats()
console.log(`Hit rate: ${stats.hitRate}%`)
console.log(`Hits: ${stats.hits}, Misses: ${stats.misses}`)resetStats()
Reset statistics counters.
redis.resetStats()Utility
flushPrefix()
Delete all keys with the configured prefix.
// ⚠️ Use with caution
await redis.flushPrefix()Usage Examples
Session Caching
import { RedisClient } from '@entro314labs/redis-client'
const redis = new RedisClient({ url: process.env.REDIS_URL })
// Store session
async function createSession(userId: string, data: SessionData) {
const sessionId = crypto.randomUUID()
await redis.set(`session:${sessionId}`, { userId, ...data }, 86400) // 24 hours
return sessionId
}
// Get session
async function getSession(sessionId: string) {
return redis.get<SessionData>(`session:${sessionId}`)
}
// Extend session
async function extendSession(sessionId: string) {
await redis.expire(`session:${sessionId}`, 86400)
}API Rate Limiting
import { RedisClient } from '@entro314labs/redis-client'
const redis = new RedisClient({ url: process.env.REDIS_URL })
export async function rateLimit(request: Request) {
const ip = request.headers.get('x-forwarded-for') || 'unknown'
// 100 requests per minute
const exceeded = await redis.rateLimit(`api:${ip}`, 100, 60)
if (exceeded) {
const remaining = await redis.getRemainingRequests(`api:${ip}`, 100, 60)
return new Response('Rate limit exceeded', {
status: 429,
headers: {
'X-RateLimit-Remaining': String(remaining),
'Retry-After': '60',
},
})
}
return null // Continue processing
}Query Caching
import { RedisClient } from '@entro314labs/redis-client'
const redis = new RedisClient({ url: process.env.REDIS_URL })
async function getWebsiteStats(websiteId: string, dateRange: DateRange) {
const cacheKey = `stats:${websiteId}:${dateRange.start}:${dateRange.end}`
return redis.fetch(
cacheKey,
async () => {
// Expensive database query
return await db.execute(sql`
SELECT * FROM website_event
WHERE website_id = ${websiteId}
AND created_at BETWEEN ${dateRange.start} AND ${dateRange.end}
`)
},
300 // Cache for 5 minutes
)
}Cache Invalidation
// When website settings change
async function updateWebsite(websiteId: string, data: UpdateData) {
await db.update(website).set(data).where(eq(website.id, websiteId))
// Invalidate all cache for this website
await redis.invalidatePattern(`website:${websiteId}:*`)
await redis.invalidatePattern(`stats:${websiteId}:*`)
}TypeScript Types
import type {
RedisClientConfig,
RedisStats,
TTLOptions,
} from '@entro314labs/redis-client'Properties
Access underlying client and state:
// Access ioredis client directly
const ioredis = redis.client
// Check connection state
const connected = redis.isConnected
// Get configured URL (masked)
const url = redis.url
// Get key prefix
const prefix = redis.prefix
// Get default TTL
const ttl = redis.defaultTTLError Handling
import { RedisClient } from '@entro314labs/redis-client'
const redis = new RedisClient({ url: process.env.REDIS_URL })
try {
await redis.get('key')
} catch (error) {
if (error instanceof Error) {
console.error('Redis error:', error.message)
}
}Requirements
- Node.js >= 22.x
- Redis 6.0+
License
MIT