redis-abstraction
Version:
A Redis client pool with abstraction to different Redis libraries.
119 lines (118 loc) • 5.48 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.RedisClientPool = void 0;
const node_crypto_1 = __importDefault(require("node:crypto"));
const node_fs_1 = __importDefault(require("node:fs"));
class RedisClientPool {
constructor(redisConnectionCreator, idlePoolSize = 6, nodeFSModule = node_fs_1.default, nodeCryptoModule = node_crypto_1.default) {
this.redisConnectionCreator = redisConnectionCreator;
this.idlePoolSize = idlePoolSize;
this.nodeFSModule = nodeFSModule;
this.nodeCryptoModule = nodeCryptoModule;
this.totalConnectionCounter = 0;
this.poolRedisClients = Array.from({ length: idlePoolSize }, (_) => redisConnectionCreator());
this.totalConnectionCounter += idlePoolSize;
this.activeRedisClients = new Map();
}
initialize() {
return __awaiter(this, void 0, void 0, function* () {
const initHandles = this.poolRedisClients.map((_) => __awaiter(this, void 0, void 0, function* () { yield _.connect(); }));
yield Promise.allSettled(initHandles);
});
}
acquire(token) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.activeRedisClients.has(token)) {
const availableClient = this.poolRedisClients.pop() || (() => { this.totalConnectionCounter += 1; return this.redisConnectionCreator(); })();
if ((availableClient.isOpen && availableClient.isReady) === false) {
//For some reason the new Redis client closes connection if the connection is left idle for a while. So we need to check if the connection is open before using it.
yield availableClient.connect();
}
this.activeRedisClients.set(token, availableClient);
}
});
}
release(token) {
return __awaiter(this, void 0, void 0, function* () {
const releasedClient = this.activeRedisClients.get(token);
if (releasedClient == undefined) {
return;
}
this.activeRedisClients.delete(token);
if (this.poolRedisClients.length < this.idlePoolSize) {
this.poolRedisClients.push(releasedClient);
}
else {
yield this.closeClient(releasedClient);
}
});
}
closeClient(client) {
return __awaiter(this, void 0, void 0, function* () {
if (typeof client.quit === "function") {
yield client.quit();
}
if (typeof client.close === "function") {
yield client.close();
}
if (typeof client.destroy === "function") {
yield client.destroy();
}
});
}
shutdown() {
return __awaiter(this, void 0, void 0, function* () {
const waitHandles = [...this.poolRedisClients, ...Array.from(this.activeRedisClients.values())]
.map((_) => __awaiter(this, void 0, void 0, function* () { return this.closeClient(_); }));
yield Promise.allSettled(waitHandles);
this.poolRedisClients = [];
this.activeRedisClients.clear();
this.totalConnectionCounter = 0;
});
}
run(token, commandArgs) {
return __awaiter(this, void 0, void 0, function* () {
const redisClient = this.activeRedisClients.get(token);
if (redisClient == undefined) {
throw new Error("Please acquire a client with proper token");
}
return yield redisClient.sendCommand(commandArgs);
});
}
pipeline(token, commands, transaction) {
return __awaiter(this, void 0, void 0, function* () {
const redisClient = this.activeRedisClients.get(token);
if (redisClient == undefined) {
throw new Error("Please acquire a client with proper token");
}
const transactionContext = redisClient.multi();
for (const cmd of commands) {
// @ts-ignore
transactionContext.addCommand(cmd);
}
return transaction === true ? yield transactionContext.exec() : yield transactionContext.execAsPipeline();
});
}
script(token, filePath, keys, args) {
throw new Error("Method not implemented.");
}
generateUniqueToken(prefix) {
return `${prefix}-${this.nodeCryptoModule.randomUUID()}`;
}
[Symbol.asyncDispose]() {
return this.shutdown();
}
}
exports.RedisClientPool = RedisClientPool;