rwadurian/backend/services/mining-service/src/infrastructure/redis/redis.service.ts

100 lines
2.7 KiB
TypeScript

import { Injectable, Inject, OnModuleInit, OnModuleDestroy, Logger } from '@nestjs/common';
import Redis from 'ioredis';
interface RedisOptions {
host: string;
port: number;
password?: string;
db?: number;
}
@Injectable()
export class RedisService implements OnModuleInit, OnModuleDestroy {
private readonly logger = new Logger(RedisService.name);
private client: Redis;
constructor(@Inject('REDIS_OPTIONS') private readonly options: RedisOptions) {}
async onModuleInit() {
this.client = new Redis({
host: this.options.host,
port: this.options.port,
password: this.options.password,
db: this.options.db ?? 16,
retryStrategy: (times) => Math.min(times * 50, 2000),
});
this.client.on('error', (err) => this.logger.error('Redis error', err));
this.client.on('connect', () => this.logger.log('Connected to Redis'));
}
async onModuleDestroy() {
await this.client.quit();
}
getClient(): Redis {
return this.client;
}
async get(key: string): Promise<string | null> {
return this.client.get(key);
}
async set(key: string, value: string, ttlSeconds?: number): Promise<void> {
if (ttlSeconds) {
await this.client.setex(key, ttlSeconds, value);
} else {
await this.client.set(key, value);
}
}
async getJson<T>(key: string): Promise<T | null> {
const value = await this.get(key);
if (!value) return null;
try {
return JSON.parse(value) as T;
} catch {
return null;
}
}
async setJson<T>(key: string, value: T, ttlSeconds?: number): Promise<void> {
await this.set(key, JSON.stringify(value), ttlSeconds);
}
async acquireLock(lockKey: string, ttlSeconds: number = 30): Promise<string | null> {
const lockValue = `${Date.now()}-${Math.random().toString(36).substring(7)}`;
const ttlMs = Math.round(ttlSeconds * 1000);
const result = await this.client.set(lockKey, lockValue, 'PX', ttlMs, 'NX');
return result === 'OK' ? lockValue : null;
}
async releaseLock(lockKey: string, lockValue: string): Promise<boolean> {
const script = `
if redis.call("get", KEYS[1]) == ARGV[1] then
return redis.call("del", KEYS[1])
else
return 0
end
`;
const result = await this.client.eval(script, 1, lockKey, lockValue);
return result === 1;
}
async incr(key: string): Promise<number> {
return this.client.incr(key);
}
async incrByFloat(key: string, increment: number): Promise<string> {
return this.client.incrbyfloat(key, increment);
}
async keys(pattern: string): Promise<string[]> {
return this.client.keys(pattern);
}
async del(key: string): Promise<number> {
return this.client.del(key);
}
}