UNPKG

redis-abstraction

Version:

A Redis client pool with abstraction to different Redis libraries.

119 lines (118 loc) 5.48 kB
"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;