npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@samuel-pro-tech/redis-helper

v1.0.1

Published

A lightweight Redis helper for Node.js providing cache-aside utilities, Pub/Sub support, and managed Redis connections.

Readme

Redis Helper

A lightweight, production-ready Redis helper library for Node.js with built-in cache-aside pattern, Pub/Sub support, circuit breaker protection, and automatic reconnection.

npm version npm license

✨ Features

  • 🚀 Cache-Aside Pattern: Built-in getOrSet() for efficient caching
  • 🛡️ Circuit Breaker: Automatic failure detection and recovery
  • 🔄 Auto-Reconnect: Resilient connection management
  • 📡 Pub/Sub Support: Publisher/Subscriber pattern implementation
  • 🏷️ Key Prefixing: Organized namespace management
  • Performance: Minimal overhead with optimal Redis operations
  • 🔧 TypeScript Ready: Full type definitions included

📦 Installation

npm install @samuel-pro-tech/redis-helper

🚀 Quick Start

import { initRedis, getOrSet, setData, getData } from '@samuel-pro-tech/redis-helper'

// Initialize Redis connection
await initRedis({
  url: 'redis://localhost:6379',
  keyPrefix: 'myapp:',
  defaultTtl: 3600 // 1 hour
})

// Cache-aside pattern: Get from cache or execute function
const userData = await getOrSet('user:123', async () => {
  // This function runs only if cache miss
  return await fetchUserFromDatabase(123)
}, 1800) // Cache for 30 minutes

// Direct cache operations
await setData('session:abc', { userId: 123, role: 'admin' }, 7200)
const session = await getData('session:abc')

🔧 Configuration

Default Configuration

const defaultConfig = {
  url: 'redis://localhost:6379',
  keyPrefix: 'myapp:',
  defaultTtl: 3600, // 1 hour in seconds
  socket: {
    reconnectStrategy: (retries) => Math.min(retries * 100, 3000),
    connectTimeout: 10000
  }
}

Custom Configuration

await initRedis({
  url: 'redis://username:password@host:port',
  keyPrefix: 'production:',
  defaultTtl: 7200,
  socket: {
    connectTimeout: 5000,
    reconnectStrategy: (retries) => Math.min(retries * 50, 1000)
  }
})

📚 API Reference

Core Functions

initRedis(config?)

Initialize Redis connection with optional configuration.

await initRedis({
  url: 'redis://localhost:6379',
  keyPrefix: 'app:',
  defaultTtl: 3600
})

getOrSet(key, handler, ttl?, parseJson?)

Cache-aside pattern: Get from cache or execute handler function.

const result = await getOrSet('expensive-query', async () => {
  return await expensiveDatabaseQuery()
}, 1800) // Cache for 30 minutes

// With custom parsing
const rawResult = await getOrSet('raw-data', async () => {
  return 'plain text data'
}, 3600, false) // Don't parse as JSON

setData(key, value, ttl?)

Store data in Redis with optional TTL.

await setData('user:123', { name: 'John', age: 30 }, 3600)
await setData('counter', 42) // Uses default TTL
await setData('permanent', 'data', 0) // No expiration

getData(key, parseJson?)

Retrieve data from Redis.

const user = await getData('user:123') // Returns parsed object
const rawData = await getData('user:123', false) // Returns string
const notFound = await getData('nonexistent') // Returns null

Data Management Functions

deleteData(key)

Delete data from Redis.

const deletedCount = await deleteData('user:123')
console.log(`Deleted ${deletedCount} keys`) // 1 if key existed, 0 if not

exists(key)

Check if key exists in Redis.

const userExists = await exists('user:123')
if (userExists) {
  console.log('User found in cache')
}

setTTL(key, ttl)

Set TTL for existing key.

const success = await setTTL('user:123', 7200) // 2 hours
console.log(success ? 'TTL set' : 'Key not found')

getTTL(key)

Get TTL for key.

const ttl = await getTTL('user:123')
if (ttl > 0) console.log(`Expires in ${ttl} seconds`)
else if (ttl === -1) console.log('No expiration set')
else if (ttl === -2) console.log('Key does not exist')

Pub/Sub Functions

publish(channel, message)

Publish message to Redis channel.

// Publish object
await publish('user-events', { 
  type: 'login', 
  userId: 123, 
  timestamp: Date.now() 
})

// Publish string
await publish('notifications', 'System maintenance in 5 minutes')

subscribe(channel, callback)

Subscribe to Redis channel.

// Subscribe to user events
await subscribe('user-events', (message) => {
  console.log('User event:', message)
  // Handle the event based on message.type
})

// Subscribe to notifications
await subscribe('notifications', (message) => {
  console.log('Notification:', message)
})

Connection Management

isRedisReady()

Check if Redis client is initialized and ready.

if (isRedisReady()) {
  console.log('Redis is connected and ready')
} else {
  console.log('Redis is not ready')
}

isAvailable()

Check if Redis is available (includes circuit breaker status).

if (isAvailable()) {
  console.log('Redis is available for operations')
} else {
  console.log('Redis unavailable (down or circuit breaker open)')
}

getRedisClient() | getRedisPublisher() | getRedisSubscriber()

Get Redis client instances for advanced operations.

// Get main client for custom commands
const client = getRedisClient()
await client.hSet('hash:key', 'field', 'value')

// Get publisher for custom pub/sub
const publisher = getRedisPublisher()
await publisher.publish('custom:channel', 'message')

// Get subscriber for custom subscriptions
const subscriber = getRedisSubscriber()
await subscriber.pSubscribe('pattern:*', (message, channel) => {
  console.log(`Pattern message from ${channel}:`, message)
})

getConfig()

Get current Redis configuration.

const config = getConfig()
console.log('Current prefix:', config.keyPrefix)
console.log('Default TTL:', config.defaultTtl)
console.log('Redis URL:', config.url)

closeRedis()

Gracefully close all Redis connections.

// Graceful shutdown
await closeRedis()
console.log('All Redis connections closed')

🛡️ Circuit Breaker

The library includes built-in circuit breaker protection:

  • Failure Threshold: 3 consecutive failures
  • Recovery Time: 30 seconds
  • Automatic Fallback: Functions continue to work even when Redis is down
// Even if Redis is down, this will execute the handler
const data = await getOrSet('key', () => fetchFromDatabase())

💡 Usage Examples

Basic Caching

import { initRedis, getOrSet, setData, getData } from '@samuel-pro-tech/redis-helper'

// Initialize
await initRedis({ keyPrefix: 'myapp:', defaultTtl: 3600 })

// Cache expensive operations
const userData = await getOrSet(`user:${userId}`, async () => {
  return await db.user.findById(userId)
}, 1800) // Cache for 30 minutes

Session Management

// Store session
await setData(`session:${sessionId}`, {
  userId: 123,
  role: 'admin',
  loginTime: Date.now()
}, 86400) // 24 hours

// Retrieve session
const session = await getData(`session:${sessionId}`)
if (session) {
  console.log('User authenticated:', session.userId)
}

// Extend session
await setTTL(`session:${sessionId}`, 86400) // Extend by 24 hours

// Logout
await deleteData(`session:${sessionId}`)

Pub/Sub Messaging

// Real-time notifications
await subscribe('user:notifications', async (notification) => {
  await sendEmailNotification(notification.email, notification.message)
})

// Send notification
await publish('user:notifications', {
  userId: 123,
  email: '[email protected]',
  message: 'Your order has been shipped!'
})

Data Analytics

// Increment counters
const client = getRedisClient()
await client.incr('myapp:page:views')
await client.hincrBy('myapp:user:stats', `user:${userId}`, 1)

// Get statistics
const pageViews = await client.get('myapp:page:views')
const userStats = await client.hGetAll('myapp:user:stats')

Background Jobs with Circuit Breaker

const processJob = async (jobData) => {
  // Try to get cached result first
  const cached = await getOrSet(`job:result:${jobData.id}`, async () => {
    // This will run even if Redis is down
    const result = await heavyProcessing(jobData)
    return result
  }, 3600)
  
  return cached
}

// Circuit breaker automatically handles Redis failures
const result = await processJob({ id: 'job-123', data: 'process-this' })

⚠️ Error Handling

Graceful Degradation

try {
  const data = await getData('user:123')
  if (data) {
    return data // Cache hit
  }
} catch (error) {
  console.error('Redis error, falling back to database:', error)
}

// Always fallback to primary data source
return await database.getUser(123)

Circuit Breaker States

// Check availability before operations
if (isAvailable()) {
  await setData('key', 'value')
} else {
  console.log('Redis circuit breaker is open, skipping cache')
}

// Use getOrSet for automatic fallback
const data = await getOrSet('key', async () => {
  return await fetchFromDatabase() // Always executes if Redis is down
})

Connection Monitoring

// Monitor connection status
setInterval(() => {
  if (isRedisReady()) {
    console.log('✅ Redis: Connected')
  } else {
    console.log('❌ Redis: Disconnected')
  }
  
  if (isAvailable()) {
    console.log('🟢 Circuit: Closed')
  } else {
    console.log('🔴 Circuit: Open')
  }
}, 30000) // Check every 30 seconds

🚀 Production Usage

Environment Setup

# .env file
REDIS_URL=redis://username:password@host:port
REDIS_PREFIX=production:
REDIS_TTL=3600
import { initRedis } from '@samuel-pro-tech/redis-helper'

await initRedis({
  url: process.env.REDIS_URL,
  keyPrefix: process.env.REDIS_PREFIX,
  defaultTtl: parseInt(process.env.REDIS_TTL)
})

Graceful Shutdown

process.on('SIGTERM', async () => {
  await closeRedis()
  process.exit(0)
})

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

📄 License

MIT License - see LICENSE file for details.

🔗 Links