UNPKG

redis-smq-common

Version:

Provides essential components and utilities shared across RedisSMQ packages.

159 lines 6.37 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.process = null; this.port = null; this.powerSwitch = new index_js_3.PowerSwitch(); this.bindExitHandler(); } bindExitHandler() { process.once('beforeExit', () => this.shutdown()); } findRedisBinary() { return __awaiter(this, void 0, void 0, function* () { try { const command = process.platform === 'win32' ? 'where redis-server' : 'which redis-server'; const { stdout } = yield execAsync(command); const path = stdout.trim(); if (path) return path; } catch (_a) { } if (yield index_js_1.env.doesPathExist(REDIS_BINARY_PATH)) { return REDIS_BINARY_PATH; } throw new index_js_4.RedisServerBinaryNotFoundError(); }); } createRedisArgs(port) { return ['--port', port.toString(), '--save', '', '--appendonly', 'no']; } waitForReady(timeoutMs) { return new Promise((resolve, reject) => { var _a; if (!this.process) { reject(new Error('Redis process not started')); return; } const timeout = setTimeout(() => { cleanup(); reject(new index_js_4.RedisServerStartupFailedError({ message: `Redis server start timeout after ${timeoutMs}ms`, })); }, timeoutMs); const onData = (data) => { if (data.toString().includes('Ready to accept connections')) { cleanup(); resolve(); } }; const onExit = () => { cleanup(); }; const onError = (error) => { cleanup(); reject(new index_js_4.RedisServerStartupFailedError({ message: `Redis process error: ${error.message}`, })); }; const cleanup = () => { var _a, _b, _c, _d; clearTimeout(timeout); (_b = (_a = this.process) === null || _a === void 0 ? void 0 : _a.stdout) === null || _b === void 0 ? void 0 : _b.removeListener('data', onData); (_c = this.process) === null || _c === void 0 ? void 0 : _c.removeListener('exit', onExit); (_d = this.process) === null || _d === void 0 ? void 0 : _d.removeListener('error', onError); }; (_a = this.process.stdout) === null || _a === void 0 ? void 0 : _a.on('data', onData); this.process.on('exit', onExit); this.process.on('error', onError); }); } waitForShutdown(timeoutMs) { return new Promise((resolve) => { if (!this.process) { resolve(); return; } const timeout = setTimeout(() => { var _a; cleanup(); (_a = this.process) === null || _a === void 0 ? void 0 : _a.kill('SIGKILL'); resolve(); }, timeoutMs); const onExit = () => { cleanup(); resolve(); }; const cleanup = () => { var _a; clearTimeout(timeout); (_a = this.process) === null || _a === void 0 ? void 0 : _a.removeListener('exit', onExit); }; this.process.once('exit', onExit); this.process.kill('SIGTERM'); }); } start(requestedPort) { return __awaiter(this, void 0, void 0, function* () { if (!this.powerSwitch.goingUp()) { throw new Error('Already started or going up'); } const redisBinary = yield this.findRedisBinary(); this.port = requestedPort || (yield index_js_2.net.getRandomPort()); this.process = (0, child_process_1.spawn)(redisBinary, this.createRedisArgs(this.port)); try { yield this.waitForReady(10000); } catch (error) { if (this.process && !this.process.exitCode && !this.process.killed) { throw error; } return this.port; } this.powerSwitch.commit(); return this.port; }); } shutdown() { return __awaiter(this, void 0, void 0, function* () { if (!this.powerSwitch.goingDown()) return; try { if (this.process) { yield this.waitForShutdown(5000); } } finally { this.process = null; this.port = null; this.powerSwitch.commit(); } }); } } exports.RedisServer = RedisServer; //# sourceMappingURL=redis-server.js.map