@asenajs/asena-redis
v1.0.0
Published
Redis integration for AsenaJS - service client and multi-pod WebSocket transport
Maintainers
Readme
@asenajs/asena-redis
Redis integration for AsenaJS — service client with built-in multi-pod WebSocket transport.
Your existing @Redis decorated service gives you full Redis operations with automatic IoC registration. For multi-pod deployments, RedisTransport synchronizes WebSocket messages across instances via Redis pub/sub.
Features
- Decorator-Based Setup -
@Redisdecorator handles IoC registration and connection lifecycle - Dual Adapter Support - Bun native
RedisClient(default) andredis(node-redis) package - Multi-Pod WebSocket Transport - Synchronize WebSocket messages across pods via Redis pub/sub
- Full Redis Operations - String, Hash, Set, Key, and raw command support
- Binary Data Support - ArrayBuffer and Uint8Array transport with Base64 encoding
- Zero Runtime Dependencies - Only peer deps (asena, reflect-metadata)
Requirements
- Bun v1.3.11 or higher
- @asenajs/asena v0.7.0 or higher
Installation
bun add @asenajs/asena-redisFor node-redis adapter (optional):
bun add @asenajs/asena-redis redisQuick Start
import { Redis, AsenaRedisService } from '@asenajs/asena-redis';
@Redis({
config: { url: 'redis://localhost:6379' },
name: 'AppRedis',
})
export class AppRedis extends AsenaRedisService {
async getOrSet(key: string, factory: () => Promise<string>, ttl?: number): Promise<string> {
const cached = await this.get(key);
if (cached) return cached;
const value = await factory();
await this.set(key, value, ttl);
return value;
}
}Asena automatically discovers it — that's it.
Now inject and use:
import { Service } from '@asenajs/asena/decorators';
import { Inject } from '@asenajs/asena/decorators/ioc';
@Service('CacheService')
export class CacheService {
@Inject('AppRedis')
private redis: AppRedis;
async getUserName(id: string): Promise<string> {
return this.redis.getOrSet(`user:${id}`, async () => {
// fetch from database...
return 'John';
}, 60);
}
}Adapter Selection
By default, @asenajs/asena-redis uses Bun's native RedisClient. For environments requiring the redis (node-redis) package:
@Redis({
config: { url: 'redis://localhost:6379' },
adapter: 'node-redis',
})
export class AppRedis extends AsenaRedisService {}| Adapter | Package | Best For |
|---------|---------|----------|
| 'bun' (default) | None (Bun built-in) | Bun runtime, maximum performance |
| 'node-redis' | redis ^5.11.0 | Node.js compatibility, Redis modules |
Multi-Pod WebSocket Transport
RedisTransport synchronizes WebSocket messages across multiple server instances using Redis pub/sub.
Setup
import { Config } from '@asenajs/asena/decorators';
import { Inject } from '@asenajs/asena/decorators/ioc';
import { RedisTransport } from '@asenajs/asena-redis';
@Config()
export class AppConfig {
@Inject('AppRedis')
private redis: AppRedis;
transport() {
return new RedisTransport(this.redis);
}
}Or without an existing Redis service:
transport() {
return new RedisTransport({ url: 'redis://localhost:6379' });
}How It Works
Each server instance gets a unique pod ID. When a WebSocket message is published:
- The message is delivered locally via
server.publish() - The message is sent to Redis pub/sub with the originating pod ID
- Other pods receive the message and deliver it to their local sockets
- Messages from the same pod are deduplicated automatically
Options
new RedisTransport(source, {
channel: 'asena:ws:transport', // Redis pub/sub channel (default)
});Configuration
interface RedisConfig {
// Connection
url?: string; // redis[s]://[[username][:password]@][host][:port][/db]
host?: string; // default: 'localhost'
port?: number; // default: 6379
username?: string;
password?: string;
db?: number;
// Timeouts & Reconnection
connectionTimeout?: number; // Connection timeout in ms (default: 10000)
idleTimeout?: number; // Idle timeout in ms (Bun only, default: 0)
autoReconnect?: boolean; // Auto-reconnect on disconnect (default: true)
maxRetries?: number; // Max reconnection attempts (default: 10)
// Behavior
enableOfflineQueue?: boolean; // Queue commands when disconnected (default: true)
enableAutoPipelining?: boolean; // Automatic command pipelining (Bun only, default: true)
// TLS
tls?: boolean | TLSOptions;
// Identification
name?: string; // Service name for logging
}Note:
idleTimeoutandenableAutoPipeliningare Bun-only features and are silently ignored when using thenode-redisadapter.
API Reference
Service Methods
String Operations
get(key)- Get string valueset(key, value, ttl?)- Set string value with optional TTL (seconds)del(...keys)- Delete keys, returns countexists(key)- Check if key existsincr(key)/decr(key)- Increment/decrement counterexpire(key, seconds)- Set expirationttl(key)- Get remaining TTLkeys(pattern)- Find keys by pattern
Hash Operations
hget(key, field)- Get hash fieldhmset(key, fields)- Set multiple hash fields (['f1', 'v1', 'f2', 'v2'])hmget(key, fields)- Get multiple hash fields
Set Operations
sadd(key, member)- Add member to setsrem(key, member)- Remove member from setsmembers(key)- Get all memberssismember(key, member)- Check membership
Raw & Lifecycle
send(command, args)- Execute raw Redis commandclient- Access underlyingRedisClientAdaptercreateSubscriber()- Create a duplicate connection for pub/subtestConnection()- Returnstrueif connecteddisconnect()- Close connection
Contributing
Contributions are welcome! Please follow these guidelines:
- Maintain test coverage for critical paths
- Follow existing code style and linting rules
- Test with both Bun and node-redis adapters
Submit a Pull Request on GitHub.
License
MIT
Support
Issues or questions? Open an issue on GitHub.
