Redis component for Midway.js framework providing comprehensive Redis database integration with support for single instances, clusters, and sentinel configurations
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
The RedisService provides the primary interface for Redis operations in Midway.js applications through dependency injection. It wraps the default Redis client instance and delegates all ioredis methods, providing seamless access to Redis functionality.
Main service wrapper implementing the full Redis interface through method delegation.
/**
* Primary Redis service for dependency injection
* Implements the full ioredis Redis interface
* Automatically connects to the default Redis client
*/
class RedisService implements Redis {
@Inject()
private serviceFactory: RedisServiceFactory;
private instance: Redis;
@Init()
async init(): Promise<void>;
defineCommand(
name: string,
definition: {
lua: string;
numberOfKeys?: number;
readOnly?: boolean;
}
): void;
}
interface RedisService extends Redis {}Automatically initializes with the default Redis client from the service factory.
/**
* Initializes the service with default Redis client
* Called automatically by Midway.js during dependency injection
* @throws MidwayCommonError if default Redis instance not found
*/
async init(): Promise<void>;Defines custom Redis commands using Lua scripts.
/**
* Defines a custom Redis command using Lua scripting
* The command becomes available as a method on the service
* @param name - Name of the custom command
* @param definition - Command definition with Lua script
*/
defineCommand(
name: string,
definition: {
lua: string;
numberOfKeys?: number;
readOnly?: boolean;
}
): void;Usage Examples:
import { RedisService } from "@midwayjs/redis";
import { Inject, Provide } from "@midwayjs/core";
@Provide()
export class CacheService {
@Inject()
redisService: RedisService;
async init() {
// Define a custom atomic increment with expire command
this.redisService.defineCommand('incrWithExpire', {
lua: `
local current = redis.call('INCR', KEYS[1])
if current == 1 then
redis.call('EXPIRE', KEYS[1], ARGV[1])
end
return current
`,
numberOfKeys: 1,
readOnly: false,
});
}
async incrementCounter(key: string, expireSeconds: number) {
// Use the custom command (TypeScript may need type assertion)
return (this.redisService as any).incrWithExpire(key, expireSeconds);
}
}The RedisService implements the complete ioredis interface, providing access to all Redis commands and operations:
// All string operations from ioredis are available
await redisService.set('key', 'value');
await redisService.get('key');
await redisService.setex('key', 60, 'value'); // Set with expiration
await redisService.incr('counter');
await redisService.mget(['key1', 'key2', 'key3']);await redisService.hset('user:123', 'name', 'John');
await redisService.hget('user:123', 'name');
await redisService.hmset('user:123', { name: 'John', age: 30 });
await redisService.hgetall('user:123');await redisService.lpush('queue', 'task1');
await redisService.rpop('queue');
await redisService.lrange('queue', 0, -1);await redisService.sadd('tags', 'redis', 'database');
await redisService.smembers('tags');
await redisService.sismember('tags', 'redis');await redisService.zadd('leaderboard', 100, 'player1');
await redisService.zrange('leaderboard', 0, 9);
await redisService.zrevrange('leaderboard', 0, 9, 'WITHSCORES');await redisService.exists('key');
await redisService.expire('key', 3600);
await redisService.ttl('key');
await redisService.del('key1', 'key2');
await redisService.keys('pattern*');import { RedisService } from "@midwayjs/redis";
import { Inject, Provide } from "@midwayjs/core";
@Provide()
export class UserService {
@Inject()
redisService: RedisService;
async cacheUser(userId: string, userData: any) {
const key = `user:${userId}`;
await this.redisService.setex(key, 3600, JSON.stringify(userData));
}
async getUser(userId: string) {
const key = `user:${userId}`;
const cached = await this.redisService.get(key);
return cached ? JSON.parse(cached) : null;
}
async deleteUser(userId: string) {
const key = `user:${userId}`;
await this.redisService.del(key);
}
}@Provide()
export class SessionService {
@Inject()
redisService: RedisService;
async createSession(sessionId: string, userData: any, ttlSeconds = 1800) {
const key = `session:${sessionId}`;
await this.redisService.setex(key, ttlSeconds, JSON.stringify(userData));
}
async getSession(sessionId: string) {
const key = `session:${sessionId}`;
const data = await this.redisService.get(key);
return data ? JSON.parse(data) : null;
}
async refreshSession(sessionId: string, ttlSeconds = 1800) {
const key = `session:${sessionId}`;
await this.redisService.expire(key, ttlSeconds);
}
async destroySession(sessionId: string) {
const key = `session:${sessionId}`;
await this.redisService.del(key);
}
}@Provide()
export class RateLimitService {
@Inject()
redisService: RedisService;
async checkRateLimit(
identifier: string,
maxRequests: number,
windowSeconds: number
): Promise<{ allowed: boolean; remaining: number }> {
const key = `rate_limit:${identifier}`;
const current = await this.redisService.incr(key);
if (current === 1) {
await this.redisService.expire(key, windowSeconds);
}
const remaining = Math.max(0, maxRequests - current);
return {
allowed: current <= maxRequests,
remaining
};
}
}The RedisService supports all ioredis event handling:
@Provide()
export class MonitorService {
@Inject()
redisService: RedisService;
async init() {
// Listen for connection events
this.redisService.on('connect', () => {
console.log('Redis connected');
});
this.redisService.on('error', (error) => {
console.error('Redis error:', error);
});
this.redisService.on('close', () => {
console.log('Redis connection closed');
});
}
}Full support for Redis transactions and pipelines:
async transferBetweenCounters(from: string, to: string, amount: number) {
const multi = this.redisService.multi();
multi.decrby(from, amount);
multi.incrby(to, amount);
const results = await multi.exec();
return results;
}
// Pipeline for bulk operations
async bulkSet(keyValuePairs: Record<string, string>) {
const pipeline = this.redisService.pipeline();
Object.entries(keyValuePairs).forEach(([key, value]) => {
pipeline.set(key, value);
});
await pipeline.exec();
}