redis-smq-common
Version:
Provides essential components and utilities shared across RedisSMQ packages.
159 lines • 6.37 kB
JavaScript
;
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