I’ve encountered this problem for Redis, Database, etc, which involves making a connections with connection strings provided by user.
interface DataStorage<LockType, DataRef> {
acquireLock(resourceName: DataRef, ttl: number): Promise<LockType>;
releaseLock(lock: LockType): Promise<void>;
createData(data: string | number | Buffer, storageKey: DataRef): Promise<DataRef>;
readData(storageKey: DataRef): Promise<string>;
updateData(storageKey: DataRef, data: string | number | Buffer): Promise<void>;
close(): Promise<void>;
}
This is my interface.
And here is the implementation example.
export class RedisStorage implements DataStorage<Lock, string> {
private client: Redis | null = null;
private redlock: Redlock | null = null;
start() {
if (!this.client) {
this.client = new Redis(process.env.REDIS_URL!);
logger.info('Redis connection established: OK', { client_status: this.client.status });
// Handle connection errors
this.client.on('error', (error) => {
logger.error('ERROR: connecting to Redis!', { error: error });
throw new RedisStorageError(`ERROR: connecting to Redis: ${error}`);
});
}
if (!this.redlock) {
this.redlock = new Redlock([this.client]);
this.redlock.on('clientError', (error) => {
logger.error('ERROR: connecting to Redlock!', { error: error });
throw new RedisStorageError(`ERROR: connecting to Redlock: ${error}`);
});
}
}
async createData(data: string | number | Buffer, storageKey: string): Promise<string> {
try {
if (!this.client) {
this.start();
}
const value = await this.client!.set(storageKey, data);
logger.info(`${value}, Data created with key: ${storageKey}`);
return storageKey;
} catch (error) {
logger.error('ERROR: creating data in redis!', { error: error });
throw new RedisStorageError('ERROR: creating data: ' + error);
}
}
Do we create seperate start method, and make a lazy initialisation or is it better to create connections in constructor itself?
Is this acceptable way below?
export class RedisBroker implements MessageBroker {
private readonly client: Redis;
private readonly subscriber: Redis;
private readonly callbacks: Map<string, (message: string) => void> = new Map();
/**
* Creates a new instance of the RedisBroker class.
* @param redisServerUrl - A string representing the URL of the Redis server to connect to.
*
* @example
* const messageBroker = new RedisBroker('redis://localhost:6379');
* await messageBroker.publish('my-channel', 'hello world');
* await messageBroker.subscribe('my-channel', (message) => {
* console.log(message);
* });
*/
constructor(redisServerUrl: string) {
this.client = new Redis(redisServerUrl, { connectTimeout: 10000 });
this.subscriber = new Redis(redisServerUrl, { connectTimeout: 10000 });
// Handle connection errors
this.client.on('error', (error) => {
throw new Error(`ERROR: connecting to Redis: ${error}`);
});
this.client.on('error', (error) => {
throw new Error(`ERROR: connecting to Redis: ${error}`);
});
// Set up message event listener on the subscriber client
this.subscriber.on('message', (channel: string, message: string) => {
const callback = this.callbacks.get(channel);
if (callback) {
logger.info(`REDIS SUB: Received message on channel: ${channel}`);
callback(message);
}
});
6