@yihuangdb/storage-object
Version:
A Node.js storage object layer library using Redis OM
143 lines • 5.34 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RedisConnection = void 0;
const redis_1 = require("redis");
const connection_pool_1 = require("./connection-pool");
class RedisConnection {
static instance;
client = null;
options;
connectPromise = null;
constructor(options = {}) {
this.options = {
// Only set url if explicitly provided or in environment
url: options.url !== undefined ? options.url : process.env.REDIS_URL,
host: options.host || 'localhost',
port: options.port || 6379,
password: options.password,
database: options.database || 0,
usePool: options.usePool,
poolSize: options.poolSize,
poolTimeout: options.poolTimeout,
idleTimeout: options.idleTimeout,
maxRetries: options.maxRetries,
retryDelay: options.retryDelay,
enableOfflineQueue: options.enableOfflineQueue,
connectionName: options.connectionName,
};
}
static getInstance(options) {
if (!RedisConnection.instance) {
RedisConnection.instance = new RedisConnection(options);
}
return RedisConnection.instance;
}
async connect() {
// Use connection pool if enabled
if (this.options.usePool !== false) {
// If we already have a pooled client, return it
if (this.client?.isOpen) {
return this.client;
}
const pool = connection_pool_1.ConnectionPool.getInstance(this.options);
const pooledClient = await pool.acquire();
// Store reference for disconnect
this.client = pooledClient;
return pooledClient;
}
if (this.client?.isOpen) {
return this.client;
}
// If already connecting, return the existing promise
if (this.connectPromise) {
return this.connectPromise;
}
// Create the connection promise
this.connectPromise = this.doConnect();
try {
const client = await this.connectPromise;
return client;
}
finally {
// Clear the promise after completion
this.connectPromise = null;
}
}
async doConnect() {
const connectionOptions = this.options.url
? {
url: this.options.url,
name: this.options.connectionName || 'storage-object',
}
: {
socket: {
host: this.options.host,
port: this.options.port,
reconnectStrategy: (retries) => {
// Exponential backoff with max delay
const maxRetries = this.options.maxRetries || 10;
const delay = this.options.retryDelay || 50;
if (retries > maxRetries) {
return new Error('Max retries reached');
}
return Math.min(retries * delay, 3000);
},
},
...(this.options.password && { password: this.options.password }),
database: this.options.database,
name: this.options.connectionName || 'storage-object',
// Enable command queueing for better concurrency
commandsQueueMaxLength: 1000,
disableOfflineQueue: this.options.enableOfflineQueue === false,
};
this.client = (0, redis_1.createClient)(connectionOptions);
this.client.on('error', (err) => {
console.error('Redis Client Error:', err);
});
this.client.on('ready', () => {
console.log('Redis client ready');
});
this.client.on('reconnecting', () => {
console.log('Redis client reconnecting...');
});
await this.client.connect();
return this.client;
}
async disconnect() {
if (this.client) {
try {
// If using pool, release the connection instead of closing it
if (this.options.usePool !== false) {
const pool = connection_pool_1.ConnectionPool.getInstance(this.options);
pool.release(this.client);
}
else if (this.client.isOpen) {
await this.client.quit();
}
}
catch (error) {
this.client = null;
this.connectPromise = null;
throw error;
}
this.client = null;
this.connectPromise = null;
}
}
static async reset() {
if (RedisConnection.instance) {
await RedisConnection.instance.disconnect();
RedisConnection.instance = null;
}
// Also reset the connection pool
connection_pool_1.ConnectionPool.reset();
}
getClient() {
if (!this.client?.isOpen) {
throw new Error('Redis client is not connected. Call connect() first.');
}
return this.client;
}
}
exports.RedisConnection = RedisConnection;
//# sourceMappingURL=connection.js.map