UNPKG

redis-smq

Version:

A simple high-performance Redis message queue for Node.js.

201 lines 8.69 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.ConsumerHeartbeat = void 0; const os = __importStar(require("os")); const redis_smq_common_1 = require("redis-smq-common"); const redis_keys_js_1 = require("../../../common/redis-keys/redis-keys.js"); const index_js_1 = require("../../../config/index.js"); const event_bus_publisher_js_1 = require("./event-bus-publisher.js"); const cpuUsageStatsRef = { cpuUsage: process.cpuUsage(), time: process.hrtime(), }; function cpuUsage() { const currentTimestamp = process.hrtime(); const currentCPUUsage = process.cpuUsage(); const timestampDiff = process.hrtime(cpuUsageStatsRef.time); const cpuUsageDiff = process.cpuUsage(cpuUsageStatsRef.cpuUsage); cpuUsageStatsRef.time = currentTimestamp; cpuUsageStatsRef.cpuUsage = currentCPUUsage; const hrtime = (time) => { return time[0] * 1e3 + time[1] / 1e6; }; const usageTime = (time) => { return time / 1000; }; return Object.assign({ percentage: ((usageTime(cpuUsageDiff.user + cpuUsageDiff.system) / hrtime(timestampDiff)) * 100).toFixed(1) }, cpuUsageDiff); } class ConsumerHeartbeat extends redis_smq_common_1.Runnable { constructor(consumer, redisClient, eventBus) { super(); this.consumer = consumer; this.logger = redis_smq_common_1.logger.getLogger(index_js_1.Configuration.getSetConfig().logger, this.constructor.name.toLowerCase()); this.redisClient = redisClient; this.logger.debug(`Initializing ConsumerHeartbeat for consumer ${consumer.getId()}`); if (eventBus) { this.logger.debug('Event bus provided, setting up event bus publisher'); (0, event_bus_publisher_js_1.eventBusPublisher)(this, eventBus, this.logger); } else { this.logger.debug('No event bus provided, skipping event bus publisher setup'); } const { keyConsumerHeartbeat } = redis_keys_js_1.redisKeys.getConsumerKeys(consumer.getId()); this.keyConsumerHeartbeat = keyConsumerHeartbeat; this.logger.debug(`Consumer heartbeat key: ${this.keyConsumerHeartbeat}`); this.timer = new redis_smq_common_1.Timer(); this.timer.on('error', (err) => { this.logger.error(`Timer error: ${err.message}`); this.emit('consumerHeartbeat.error', err); }); this.logger.info(`ConsumerHeartbeat initialized for consumer ${consumer.getId()}`); } getLogger() { return this.logger; } getPayload() { this.logger.debug('Generating heartbeat payload'); const timestamp = Date.now(); const payload = { timestamp, data: { ram: { usage: process.memoryUsage(), free: os.freemem(), total: os.totalmem(), }, cpu: cpuUsage(), }, }; this.logger.debug(`Heartbeat payload generated with timestamp ${timestamp}`); return payload; } beat() { this.logger.debug('Starting heartbeat cycle'); const redisClient = this.redisClient.getInstance(); if (redisClient instanceof Error) { this.logger.error(`Failed to get Redis client instance: ${redisClient.message}`); this.emit('consumerHeartbeat.error', redisClient); return void 0; } const heartbeatPayload = this.getPayload(); const consumerId = this.consumer.getId(); const timestamp = Date.now(); const heartbeatPayloadStr = JSON.stringify(heartbeatPayload); this.logger.debug(`Setting heartbeat in Redis with TTL ${ConsumerHeartbeat.heartbeatTTL}ms`); redisClient.set(this.keyConsumerHeartbeat, heartbeatPayloadStr, { expire: { mode: 'PX', value: ConsumerHeartbeat.heartbeatTTL, }, }, (err) => { if (err) { this.logger.error(`Failed to set heartbeat in Redis: ${err.message}`); this.emit('consumerHeartbeat.error', err); } else { this.logger.debug(`Heartbeat successfully set in Redis for consumer ${consumerId}`); this.emit('consumerHeartbeat.heartbeat', consumerId, timestamp, heartbeatPayload); this.logger.debug('Scheduling next heartbeat in 1000ms'); this.timer.setTimeout(() => this.beat(), 1000); } }); } goingUp() { this.logger.info('ConsumerHeartbeat going up'); return super.goingUp().concat([ (cb) => { this.logger.debug('Setting up initial heartbeat'); const cleanUp = () => { this.logger.debug('Cleaning up heartbeat listeners'); this.removeListener('consumerHeartbeat.heartbeat', onHeartbeat); this.removeListener('consumerHeartbeat.error', onError); }; const onError = (err) => { this.logger.error(`Error during initial heartbeat: ${err === null || err === void 0 ? void 0 : err.message}`); cleanUp(); cb(err); }; const onHeartbeat = () => { this.logger.debug('Initial heartbeat successful'); cleanUp(); cb(); }; this.once('consumerHeartbeat.heartbeat', onHeartbeat); this.once('consumerHeartbeat.error', onError); this.logger.debug('Initiating first heartbeat'); this.beat(); }, ]); } goingDown() { this.logger.info('ConsumerHeartbeat going down'); return [ (cb) => { this.logger.debug('Resetting timer'); this.timer.reset(); const redisClient = this.redisClient.getInstance(); if (redisClient instanceof Error) { this.logger.warn(`Could not get Redis client during shutdown: ${redisClient.message}`); return cb(); } this.logger.debug(`Deleting heartbeat key ${this.keyConsumerHeartbeat} from Redis`); redisClient.del(this.keyConsumerHeartbeat, (err) => { if (err) { this.logger.warn(`Error deleting heartbeat key: ${err.message} (ignoring)`); } else { this.logger.debug('Heartbeat key successfully deleted from Redis'); } cb(); }); }, ].concat(super.goingDown()); } static isConsumerAlive(redisClient, consumerId, cb) { const { keyConsumerHeartbeat } = redis_keys_js_1.redisKeys.getConsumerKeys(consumerId); redisClient.get(keyConsumerHeartbeat, (err, heartbeat) => { if (err) return cb(err); const isAlive = !!heartbeat; cb(null, isAlive); }); } } exports.ConsumerHeartbeat = ConsumerHeartbeat; ConsumerHeartbeat.heartbeatTTL = 10 * 1000; //# sourceMappingURL=consumer-heartbeat.js.map