UNPKG

redis-smq-common

Version:

Provides essential components and utilities shared across RedisSMQ packages.

136 lines 5.74 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.WorkerCluster = void 0; const index_js_1 = require("../../errors/index.js"); const index_js_2 = require("../../redis-lock/index.js"); const index_js_3 = require("../../runnable/index.js"); const worker_handler_js_1 = require("./worker-handler.js"); const worker_loader_js_1 = require("./worker-loader.js"); class WorkerCluster extends index_js_3.Runnable { constructor(redisClient, logger, uniqueGroupIdentifier, workerFilenamePattern = '.worker.js') { super(); this.uniqueGroupIdentifier = null; this.locker = null; this.acquireLock = (cb) => { if (!this.locker) return cb(); if (!this.isOperational()) { cb(new Error('Resource group is shutting down')); return; } this.logger.debug('Attempting to acquire lock...'); this.locker.acquireLock((err) => { var _a; if (!err) { this.logger.debug(`Lock acquired successfully (Lock ID: ${(_a = this.locker) === null || _a === void 0 ? void 0 : _a.getId()})`); return cb(); } if (err instanceof index_js_2.LockNotAcquiredError) { this.logger.warn('Could not acquire lock (already locked by another instance)'); return cb(new index_js_1.AbortError()); } this.logger.error(`Failed to acquire lock: ${err.message}`, err); cb(err); }); }; this.releaseLock = (cb) => { if (!this.locker) return cb(); this.logger.debug('Releasing lock...'); this.locker.releaseLock((err) => { if (err) { this.logger.error(`Failed to release lock: ${err.message}`, err); } else { this.logger.debug('Lock released successfully'); } cb(err); }); }; this.loadFromDir = (workersDir, payload, cb) => { const stateError = this.validateDownState('load workers'); if (stateError) { cb(stateError); return; } if (this.workerHandler.hasWorkers()) { this.logger.warn('Cannot load workers: Workers already exist in resource group'); cb(new Error('Workers already exist, cannot load new ones')); return; } this.logger.debug(`Loading workers from directory: ${workersDir}`); this.workerLoader.loadFromDirectory(workersDir, payload, (err) => { if (!err) { this.logger.debug(`Successfully loaded workers from ${workersDir}`); } cb(err); }); }; this.logger = logger.createLogger(this.constructor.name); this.redisClient = redisClient; this.workerHandler = new worker_handler_js_1.WorkerHandler({ logger: this.logger }); this.workerLoader = new worker_loader_js_1.WorkerLoader(this.logger, workerFilenamePattern, this.handleWorkerError.bind(this), this.workerHandler); this.uniqueGroupIdentifier = uniqueGroupIdentifier; if (this.uniqueGroupIdentifier) { this.logger.debug(`Creating RedisLock for resource group: ${this.uniqueGroupIdentifier}`); this.locker = new index_js_2.RedisLock(this.redisClient, this.logger, this.uniqueGroupIdentifier, WorkerCluster.LOCK_TTL, true, true); this.locker.on('locker.error', (err) => { this.logger.error(`Locker error: ${err.message}`, err); this.handleError(err); }); } this.logger.debug(`WorkerCluster initialized`); } handleWorkerError(err, filename) { this.logger.error(`Worker error from ${filename}: ${err.message}`, err); this.handleError(err); } goingUp() { this.logger.debug('WorkerCluster going up...'); return [ ...super.goingUp(), this.acquireLock, (cb) => this.workerHandler.run(cb), ]; } goingDown() { this.logger.debug('WorkerCluster going down...'); return [ (cb) => this.workerHandler.shutdown(cb), this.releaseLock, ...super.goingDown(), ]; } handleError(err) { if (!this.isOperational()) return; this.logger.error(`WorkerCluster error: ${err.message}`, err); this.emit('workerCluster.error', err); super.handleError(err); } addWorker(filename, payload) { this.assertDownState('add workers'); this.logger.debug(`Adding worker from file: ${filename}`); const worker = this.workerLoader.createWorker(filename, payload); this.emit('workerCluster.workerAdded', worker); return worker; } assertDownState(operation) { const err = this.validateDownState(operation); if (err) throw err; } validateDownState(operation) { if (!this.isDown()) { this.logger.warn(`Cannot ${operation}: Resource group is not in DOWN state`); return new Error(`Resource group must be in DOWN state to ${operation}`); } if (this.isGoingUp()) { this.logger.warn(`Cannot ${operation}: Resource group is going up`); return new Error(`Cannot ${operation} while going up`); } } } exports.WorkerCluster = WorkerCluster; WorkerCluster.LOCK_TTL = 60000; //# sourceMappingURL=worker-cluster.js.map