A powerful and feature-rich Redis client wrapper for Deno applications with v2 API improvements.
Built on top of node-redis
, this library simplifies Redis operations while adding advanced features
like middleware support, metrics collection, batch operations, and enhanced stream processing.
- 🔄 Redis Pub/Sub messaging system
- 📊 Enhanced Redis Streams with batch operations and dead letter queues
- 📝 Hash and String operations with middleware support
- 🔑 Flexible authentication with connection pooling
- 🔌 Automatic connection management with retry strategies
- 🚀 Event-driven architecture with metrics collection
- 💪 Full TypeScript support with type definitions
- 🎯 Fluent configuration API
- 📈 Built-in observability (metrics, health checks)
- 🔧 Middleware pipeline for cross-cutting concerns
- ⚡ Pipeline and transaction support
- 🔍 Advanced querying (scan, keys, mget/mset)
import { RedisClient } from "@nelreina/redis-client";
// TypeScript users get full type support automatically
// Basic initialization
const redis = new RedisClient({
redisHost: "localhost",
redisPort: 6379,
redisUser: "optional_username",
redisPw: "optional_password",
serviceName: "my-service",
enableMetrics: true, // Enable metrics collection
connectionRetries: 3, // Retry connection 3 times
connectionRetryDelay: 1000, // Wait 1s between retries
logger: customLogger, // Optional: pass custom logger
});
// Fluent configuration
const redis = new RedisClient({ redisHost: "localhost" })
.withConnectionPool(5)
.withRetries(3, 2000)
.withMetrics(true)
.withLogger(customLogger);
// Custom logger example
const customLogger = {
info: (message, ...args) => console.log(`[INFO] ${message}`, ...args),
error: (message, ...args) => console.error(`[ERROR] ${message}`, ...args),
warn: (message, ...args) => console.warn(`[WARN] ${message}`, ...args),
debug: (message, ...args) => console.debug(`[DEBUG] ${message}`, ...args),
};
Subscribe to a Redis channel:
await redis.subscribe2RedisChannel("my-channel", (message) => {
console.log("Received message:", message);
});
Publish to a Redis channel:
await redis.publish2RedisChannel("my-channel", {
event: "user-login",
data: { userId: "123" },
});
Connect to an event stream with v2 configuration:
// Simple usage (backward compatible)
await redis.connectToEventStream(
"my-stream",
(event) => {
console.log("Stream event:", event);
},
true, // All events
);
// Advanced configuration
await redis.connectToEventStream("my-stream", {
handler: (event) => console.log("Event:", event),
events: ["user-registered", "order-created"], // Filter specific events
startID: "$", // Start from latest
consumer: "worker-1",
group: "my-group",
blockTimeout: 5000, // Block for 5s when reading
autoAck: true, // Auto acknowledge messages
retries: 3, // Retry failed messages 3 times
deadLetterStream: "dlq:my-stream", // Send failed messages here
metrics: true, // Enable stream metrics
});
Publish to a stream:
// Single event
await redis.publishToStream(
"my-stream",
"user-registered",
"user-123",
{ email: "user@example.com" },
);
// Batch publishing for better performance
await redis.publishBatchToStream("my-stream", [
{
event: "user-registered",
aggregateId: "user-123",
payload: { email: "user1@example.com" },
},
{
event: "user-registered",
aggregateId: "user-124",
payload: { email: "user2@example.com" },
},
]);
Set hash values:
await redis.setHashValue("user:123", {
name: "John Doe",
email: "john@example.com",
role: "admin",
});
Get all hash values from a set:
const users = await redis.getAllSetHashValues("users");
Basic operations:
// Get/Set with optional expiration
await redis.set("key", "value");
await redis.set("session:123", "data", { EX: 3600 }); // Expire in 1 hour
const value = await redis.get("key");
// Check existence and manage TTL
const exists = await redis.exists("key"); // Returns 1 if exists
await redis.expire("key", 300); // Expire in 5 minutes
const ttl = await redis.ttl("key"); // Get remaining TTL
// Delete keys
await redis.del("key"); // Delete single key
await redis.del(["key1", "key2", "key3"]); // Delete multiple
// Batch operations
const values = await redis.mget(["key1", "key2", "key3"]);
await redis.mset({
"key1": "value1",
"key2": "value2",
"key3": "value3",
});
Set-based string operations:
await redis.setStringValue("active-sessions", "session:123", "user-data");
const sessions = await redis.getAllStringValues("active-sessions");
await redis.clearStringValues("active-sessions");
// Find all keys matching a pattern
const userKeys = await redis.keys("user:*");
// Scan keys efficiently (for large datasets)
for await (const keys of redis.scan("session:*", 100)) {
console.log("Found keys:", keys);
}
// Pipeline for batch operations
const pipeline = redis.pipeline();
pipeline.get("key1");
pipeline.set("key2", "value2");
pipeline.incr("counter");
const results = await pipeline.exec();
// Transaction with watch
await redis.watch("balance");
const transaction = redis.transaction();
const balance = await redis.get("balance");
transaction.set("balance", parseInt(balance) - 100);
transaction.incr("transactions");
const results = await transaction.exec();
// Add logging middleware
redis.use(async (operation, args, next) => {
console.log(`Executing ${operation} with args:`, args);
const start = Date.now();
const result = await next();
console.log(`${operation} took ${Date.now() - start}ms`);
return result;
});
// Add authentication middleware
redis.use(async (operation, args, next) => {
if (sensitiveOperations.includes(operation)) {
await validateAuth();
}
return next();
});
const health = await redis.getHealth();
console.log(health);
// {
// status: 'healthy',
// connections: { main: true, pubsub: true },
// timestamp: '2024-01-01T00:00:00.000Z'
// }
// Stream-specific health
const streamHealth = await redis.getStreamHealth("my-stream");
console.log(streamHealth);
// {
// exists: true,
// length: 1000,
// groups: 2,
// consumers: 5,
// pending: 10
// }
// Enable metrics
const redis = new RedisClient({ enableMetrics: true });
// Get metrics
const metrics = redis.getMetrics();
console.log(metrics);
// {
// operations: { total: 1000, successful: 995, failed: 5 },
// latency: { avg: 2.5, p50: 2, p95: 5, p99: 10 },
// connections: { active: 1, idle: 0, total: 1 },
// streams: {
// 'my-stream': { published: 100, consumed: 95, errors: 2 }
// }
// }
// Stream-specific metrics
const streamMetrics = redis.getStreamMetrics("my-stream");
The client includes comprehensive error handling:
- Connection errors with automatic retry and backoff
- JSON parsing errors are caught and handled gracefully
- Middleware can intercept and handle errors
- Stream processing errors can be sent to dead letter queues
- All operations return detailed error information
The v2 API is mostly backward compatible. Key changes:
- Stream configuration now supports an options object
- New methods require explicit connection handling
- Metrics and middleware are opt-in features
- Some methods now return more detailed responses
- Enable metrics in production for monitoring and debugging
- Use pipelines for batch operations to reduce network round trips
- Configure retry strategies based on your reliability requirements
- Use middleware for cross-cutting concerns like logging and auth
- Monitor stream health to prevent backlogs and memory issues
- Use batch publishing for high-throughput scenarios
MIT
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add some amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
For more information or issues, please open an issue in the repository.