UNPKG

redis-smq-common

Version:

Provides essential components and utilities shared across RedisSMQ packages.

183 lines 6.35 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Runnable = void 0; const uuid_1 = require("uuid"); const index_js_1 = require("../async/index.js"); const index_js_2 = require("../errors/index.js"); const index_js_3 = require("../event/index.js"); const index_js_4 = require("../power-switch/index.js"); const with_optional_callback_js_1 = require("../async/with-optional-callback.js"); class Runnable extends index_js_3.EventEmitter { constructor(forceShutdownOnError = true) { super(); this.waitingForUpCallbacks = []; this.waitingForDownCallbacks = []; this.id = (0, uuid_1.v4)(); this.powerSwitch = new index_js_4.PowerSwitch(); this.forceShutdownOnError = forceShutdownOnError; } goingUp() { this.logger.debug(`Going up`); return []; } goingDown() { this.logger.debug(`Going down`); return []; } finalizeUp() { if (!this.powerSwitch.commit()) { const err = new Error('Failed to commit "up" state'); this.flushWaitingForUp(err); return; } this.flushWaitingForUp(); this.logger.debug(`Up and running`); } finalizeDown() { this.powerSwitch.commit(); this.flushWaitingForUp(new Error('Runnable has been shut down')); this.flushWaitingForDown(); this.logger.debug(`Completely shut down`); } handleError(err) { if (!this.isOperational()) return; this.logger.error(err); this.shutdown(() => void 0); } flushWaitingForUp(error) { const callbacks = this.waitingForUpCallbacks; this.waitingForUpCallbacks = []; for (const cb of callbacks) { try { cb(error !== null && error !== void 0 ? error : null); } catch (e) { this.logger.error('Error in waitingForUp callback:', e); } } } flushWaitingForDown(error) { const callbacks = this.waitingForDownCallbacks; this.waitingForDownCallbacks = []; for (const cb of callbacks) { try { cb(error !== null && error !== void 0 ? error : null); } catch (e) { this.logger.error('Error in waitingForDown callback:', e); } } } executeGoingUpTasks() { const tasks = this.goingUp().map((task) => (taskCb) => { if (!this.isGoingUp()) { return taskCb(new index_js_2.AbortError({ message: 'Startup aborted' })); } task((err) => { if (!this.isGoingUp()) { taskCb(new index_js_2.AbortError({ message: 'Startup aborted by shutdown' })); } else { taskCb(err); } }); }); index_js_1.async.series(tasks, (err) => { if (!this.isGoingUp()) { return this.flushWaitingForUp(new index_js_2.AbortError({ message: 'Startup aborted by shutdown' })); } if (err) { this.powerSwitch.rollback(); this.flushWaitingForUp(err); if (this.forceShutdownOnError) this.executeGoingDownTasks(); return; } this.finalizeUp(); }); } executeGoingDownTasks() { index_js_1.async.series(this.goingDown(), (taskErr) => { if (taskErr) { this.logger.error('Error in goingDown tasks:', taskErr); } this.finalizeDown(); }); } isOperational() { return this.isGoingUp() || (this.isUp() && !this.isGoingDown()); } isRunning() { return this.powerSwitch.isRunning(); } isGoingUp() { return this.powerSwitch.isGoingUp(); } isGoingDown() { return this.powerSwitch.isGoingDown(); } isUp() { return this.powerSwitch.isUp(); } isDown() { return this.powerSwitch.isDown(); } run(cb) { return (0, with_optional_callback_js_1.withOptionalCallback)(cb, (callback) => { if (this.isRunning()) return callback(null); if (this.isGoingUp()) return void this.waitingForUpCallbacks.push(callback); if (this.isGoingDown()) return callback(new Error('Cannot run: shutdown is in progress')); if (!this.powerSwitch.goingUp()) { return callback(new Error('Cannot initiate startup – invalid state transition')); } this.waitingForUpCallbacks.push(callback); this.executeGoingUpTasks(); }); } shutdown(cb) { return (0, with_optional_callback_js_1.withOptionalCallback)(cb, (callback) => { this.waitingForDownCallbacks.push(callback); if (this.isGoingDown()) return; if (!this.isOperational()) { this.flushWaitingForDown(); return; } if (this.isGoingUp()) { this.powerSwitch.rollback(); this.flushWaitingForUp(new index_js_2.AbortError({ message: 'Startup aborted by shutdown' })); this.executeGoingDownTasks(); return; } if (!this.powerSwitch.goingDown()) { this.flushWaitingForDown(new Error('Cannot initiate shutdown – invalid state transition')); return; } this.executeGoingDownTasks(); }); } ensureIsOperational(cb) { return (0, with_optional_callback_js_1.withOptionalCallback)(cb, (callback) => { if (this.isGoingDown()) { return callback(new index_js_2.AbortError({ message: 'Shutdown in progress' })); } if (this.isRunning()) { return callback(null); } if (this.isGoingUp()) { this.waitingForUpCallbacks.push((err) => callback(err)); return; } this.run(callback); }); } getId() { return this.id; } } exports.Runnable = Runnable; //# sourceMappingURL=runnable.js.map