UNPKG

redis-smq-common

Version:

RedisSMQ Common Library provides many components that are mainly used by RedisSMQ and RedisSMQ Monitor.

156 lines 7.43 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()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.RedisServer = void 0; const child_process_1 = require("child_process"); const node_child_process_1 = require("node:child_process"); const node_util_1 = require("node:util"); const index_js_1 = require("../env/index.js"); const index_js_2 = require("../net/index.js"); const index_js_3 = require("../power-switch/index.js"); const constants_js_1 = require("./constants.js"); const index_js_4 = require("./errors/index.js"); const { REDIS_BINARY_PATH } = constants_js_1.constants; const execAsync = (0, node_util_1.promisify)(node_child_process_1.exec); class RedisServer { constructor() { this.redisBinaryPath = null; this.redisChildProcess = null; this.redisPort = null; this.powerSwitch = new index_js_3.PowerSwitch(); this.handleProcessExit = () => __awaiter(this, void 0, void 0, function* () { yield this.shutdown(); }); this.setupGlobalProcessListeners(); } setupGlobalProcessListeners() { process.on('SIGINT', this.handleProcessExit); process.on('SIGTERM', this.handleProcessExit); } waitForRedisServerStartup() { return __awaiter(this, void 0, void 0, function* () { return new Promise((resolve, reject) => { var _a, _b, _c, _d; const timeout = setTimeout(() => { cleanUp(); reject(new Error('Redis server start timeout')); }, RedisServer.STARTUP_TIMEOUT); const onData = (data) => { if (data.toString().includes('Ready to accept connections')) { cleanUp(); resolve(Number(this.redisPort)); } }; const onError = (error) => { cleanUp(); reject(error); }; const onExit = (code) => { cleanUp(); reject(new Error(`Redis server exited with code ${code}`)); }; (_b = (_a = this.redisChildProcess) === null || _a === void 0 ? void 0 : _a.stdout) === null || _b === void 0 ? void 0 : _b.on('data', onData); (_c = this.redisChildProcess) === null || _c === void 0 ? void 0 : _c.on('error', onError); (_d = this.redisChildProcess) === null || _d === void 0 ? void 0 : _d.on('exit', onExit); const cleanUp = () => { var _a, _b, _c, _d; clearTimeout(timeout); (_b = (_a = this.redisChildProcess) === null || _a === void 0 ? void 0 : _a.stdout) === null || _b === void 0 ? void 0 : _b.removeListener('data', onData); (_c = this.redisChildProcess) === null || _c === void 0 ? void 0 : _c.removeListener('error', onError); (_d = this.redisChildProcess) === null || _d === void 0 ? void 0 : _d.removeListener('exit', onExit); }; }); }); } setupChildProcessListeners() { var _a, _b, _c, _d; (_b = (_a = this.redisChildProcess) === null || _a === void 0 ? void 0 : _a.stderr) === null || _b === void 0 ? void 0 : _b.on('data', (data) => { console.error(`Redis stderr (${this.redisPort}): ${data.toString().trim()}`); }); (_c = this.redisChildProcess) === null || _c === void 0 ? void 0 : _c.on('error', () => this.shutdown()); (_d = this.redisChildProcess) === null || _d === void 0 ? void 0 : _d.on('exit', () => this.shutdown()); } fetchSystemWideRedisBinaryPath() { return __awaiter(this, void 0, void 0, function* () { try { const { stdout } = yield execAsync('which redis-server || where redis-server'); return stdout.trim() || null; } catch (_a) { return null; } }); } getRedisServerBinaryPath() { return __awaiter(this, void 0, void 0, function* () { const systemWideBinaryPath = yield this.fetchSystemWideRedisBinaryPath(); if (systemWideBinaryPath) return systemWideBinaryPath; if (yield index_js_1.env.doesPathExist(REDIS_BINARY_PATH)) { return REDIS_BINARY_PATH; } return null; }); } start(port) { return __awaiter(this, void 0, void 0, function* () { const goingUp = this.powerSwitch.goingUp(); if (!goingUp) { throw new Error('Cannot start Redis server while it is already running.'); } this.redisBinaryPath = yield this.getRedisServerBinaryPath(); if (!this.redisBinaryPath) { throw new index_js_4.RedisServerBinaryNotFoundError(); } this.redisPort = port !== null && port !== void 0 ? port : (yield index_js_2.net.getRandomPort()); this.redisChildProcess = (0, child_process_1.spawn)(this.redisBinaryPath, [ '--appendonly', 'no', '--save', '', '--port', this.redisPort.toString(), ]); this.setupChildProcessListeners(); yield this.waitForRedisServerStartup(); this.powerSwitch.commit(); return this.redisPort; }); } shutdown() { return __awaiter(this, void 0, void 0, function* () { const goingDown = this.powerSwitch.goingDown(); if (!goingDown) return; yield new Promise((resolve, reject) => { var _a, _b; const timeout = setTimeout(() => { var _a; (_a = this.redisChildProcess) === null || _a === void 0 ? void 0 : _a.kill('SIGKILL'); reject(new Error('Redis server did not shut down gracefully.')); }, RedisServer.SHUTDOWN_TIMEOUT); const cleanUp = () => { clearTimeout(timeout); this.redisChildProcess = null; this.redisPort = null; resolve(); }; (_a = this.redisChildProcess) === null || _a === void 0 ? void 0 : _a.once('close', cleanUp); (_b = this.redisChildProcess) === null || _b === void 0 ? void 0 : _b.kill('SIGTERM'); }); this.powerSwitch.commit(); }); } } exports.RedisServer = RedisServer; RedisServer.STARTUP_TIMEOUT = 10000; RedisServer.SHUTDOWN_TIMEOUT = 5000; //# sourceMappingURL=redis-server.js.map