@bts-soft/cache
v1.0.4
Published
A NestJS Redis cache and utility module providing advanced Redis operations, configuration, and health checks with built-in support for CacheManager and Redis client.
Downloads
251
Maintainers
Readme
@bts-soft/cache
A lightweight and flexible Redis-based caching package for NestJS applications.
It provides an easy way to integrate Redis caching, manage keys, handle lists, and use advanced features like distributed locks and scoring systems.
Features
Simple Redis integration for NestJS
Cache management with TTL support
Key and list utilities for structured Redis data
Distributed locking support for concurrency control
Easy configuration via environment variables
Compatible with NestJS dependency injection
Installation
npm install @bts-soft/cacheOr using Yarn:
yarn add @bts-soft/cacheMake sure you have a Redis instance running locally or remotely.
Setup in NestJS
Register the cache module globally in your NestJS application.
import { CacheModule } from '@nestjs/cache-manager';
import { Module } from '@nestjs/common';
import { RedisConfigService } from '@bts-soft/cache';
@Module({
imports: [
CacheModule.registerAsync({
useClass: RedisConfigService,
isGlobal: true,
}),
],
})
export class AppModule {}Configuration
The RedisConfigService reads Redis configuration from environment variables.
| Variable | Description | Default |
| ------------ | ----------------------- | -------------- |
| REDIS_HOST | Redis host address | localhost |
| REDIS_PORT | Redis port number | 6379 |
| REDIS_TTL | Default cache TTL (sec) | 3600 (1 hour) |
Example .env file:
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_TTL=3600Usage Example
Basic Caching
import { Injectable } from '@nestjs/common';
import { RedisService } from '@bts-soft/cache';
@Injectable()
export class ExampleService {
constructor(private readonly redisService: RedisService) {}
async getCachedValue(key: string): Promise<any> {
const cached = await this.redisService.get(key);
if (cached) return cached;
const data = await this.fetchFromDatabase();
await this.redisService.set(key, data, 3600); // cache for 1 hour
return data;
}
private async fetchFromDatabase() {
return { message: 'Hello from DB' };
}
}List and Score Utilities
The package supports managing list-based structures and scoring systems via constants.
Example constants:
export enum ListConstant {
CAMPAIGNS = 'campaigns',
USERS = 'users',
}
export enum SCORE {
HIGH = 100,
MEDIUM = 50,
LOW = 10,
}Example usage:
await this.redisService.addToList(ListConstant.CAMPAIGNS, campaignId);
await this.redisService.setScore('user:123', SCORE.HIGH);Distributed Lock Example
async handleCriticalSection(): Promise<void> {
const lockKey = 'critical:process';
const lock = await this.redisService.acquireLock(lockKey, 5000); // 5 seconds
if (!lock) {
throw new Error('Could not acquire lock');
}
try {
// safely perform critical logic
} finally {
await this.redisService.releaseLock(lockKey);
}
}API Reference
RedisService
|Method|Description|
|---|---|
|get(key: string)|Get a value by key|
|set(key: string, value: any, ttl?: number)|Set a value with optional TTL|
|delete(key: string)|Delete a key|
|addToList(list: string, value: any)|Add a value to a Redis list|
|removeFromList(list: string, value: any)|Remove a value from a Redis list|
|acquireLock(key: string, ttl: number)|Acquire a distributed lock|
|releaseLock(key: string)|Release a distributed lock|
Example Integration
In your main application entry point (main.ts):
import * as graphqlUploadExpress from 'graphql-upload/graphqlUploadExpress.js';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.use(graphqlUploadExpress({ maxFileSize: 1000000, maxFiles: 2 }));
await app.listen(3000);
}
bootstrap();Logging
The RedisService uses NestJS Logger internally for error tracking and debugging.
Make sure your application logger is configured to view Redis logs if needed.
2. Advanced Data Structure Usage
Your RedisService supports native Redis data structures, which is a major advantage.
Hash Maps (HSET)
Used for storing fields and values within a single key, ideal for user profiles or large objects.
async updateUserInfo(userId: string, key: string, value: any) {
// Sets a field in the hash map: 'user:123' { "email": "..." }
await this.redisService.hSet(`user:${userId}`, key, value);
}
async getUserFields(userId: string) {
// Retrieves all fields and values from the hash map, automatically parsed
return this.redisService.hGetAll(`user:${userId}`);
}Sorted Sets (ZADD)
Used for leaderboards, ranking, or time-series data.
// Add user to a leaderboard with a score
await this.redisService.zAdd('global:leaderboard', 1500, 'user:A');
await this.redisService.zAdd('global:leaderboard', 2200, 'user:B');
// Get the top 10 users (reverse range based on score)
const topUsers = await this.redisService.zRevRange('global:leaderboard', 0, 9);Distributed Locking
Essential for ensuring only one instance of a worker or microservice processes a task (using SET NX PX and Lua scripts).
const lockKey = `job:process:${jobId}`;
const lockValue = Math.random().toString();
const ttlMs = 5000; // Lock for 5 seconds
// Try to acquire the lock
const acquired = await this.redisService.acquireLock(lockKey, lockValue, ttlMs);
if (acquired) {
try {
// Process the task...
} finally {
// Release the lock only if we are the owner
await this.redisService.releaseLock(lockKey, lockValue);
}
}Pub/Sub (Publish/Subscribe)
Used for real-time communication between services without polling.
TypeScript
// Service A (Publisher)
await this.redisService.publish('user_events', { type: 'USER_CREATED', id: 456 });
// Service B (Subscriber)
this.redisService.subscribe('user_events', (message, channel) => {
console.log(`Received event on ${channel}:`, message);
// message is already parsed JSON thanks to the wrapper
});Core Features Summary
|Category|Methods Provided (Examples)|Underlying Redis Structure|
|---|---|---|
|Basic Caching|set, get, del, update|Key-Value (Standard)|
|String Operations|incr, decr, append, strlen|String|
|Hash Maps|hSet, hGet, hGetAll, hDel, hIncrBy|Hash|
|Sets|sAdd, sRem, sMembers, sInter|Set|
|Sorted Sets|zAdd, zRange, zScore, zIncrBy|Sorted Set|
|Lists/Queues|lPush, rPush, lPop, lRange|List|
|Transactions|multiExecute, watch, withTransaction|Multi, Exec, Watch|
|Distributed Locks|acquireLock, releaseLock, waitForLock|Lua Scripting, SET NX PX|
|Utilities|exists, ttl, expire|Utility Commands|
|Messaging|publish, subscribe, unsubscribe|Pub/Sub|
|Geospatial|geoAdd, geoPos, geoDist|Geospatial (ZSET)|
License
This package is licensed under the MIT License.
Contact
Author: Omar Sabry
Email: [email protected]
LinkedIn: Omar Sabry
Portfolio: Portfolio
Repository
GitHub: Github Repo
