UNPKG

redis-smq

Version:

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

137 lines 5.59 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ConsumerHeartbeat = void 0; const os = require("os"); const redis_smq_common_1 = require("redis-smq-common"); const events_1 = require("../../common/events/events"); const redis_keys_1 = require("../../common/redis-keys/redis-keys"); const events_2 = require("events"); const redis_smq_common_2 = require("redis-smq-common"); 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 events_2.EventEmitter { constructor(consumer, redisClient) { super(); this.redisClient = redisClient; this.consumer = consumer; const { keyHeartbeats } = consumer.getRedisKeys(); this.keyHeartbeats = keyHeartbeats; this.keyHeartbeatTimestamps = redis_keys_1.redisKeys.getMainKeys().keyHeartbeatConsumerWeight; this.ticker = new redis_smq_common_1.Ticker(() => this.onTick()); this.ticker.nextTick(); } getPayload() { const timestamp = Date.now(); return { timestamp, data: { ram: { usage: process.memoryUsage(), free: os.freemem(), total: os.totalmem(), }, cpu: cpuUsage(), }, }; } onTick() { const timestamp = Date.now(); const heartbeatPayload = this.getPayload(); const heartbeatPayloadStr = JSON.stringify(heartbeatPayload); const multi = this.redisClient.multi(); multi.hset(this.keyHeartbeats, this.consumer.getId(), heartbeatPayloadStr); multi.zadd(this.keyHeartbeatTimestamps, timestamp, this.consumer.getId()); multi.exec((err) => { if (err) this.emit(events_1.events.ERROR, err); else { this.emit(events_1.events.TICK, timestamp, this.consumer.getId(), heartbeatPayload); this.ticker.nextTick(); } }); } quit(cb) { redis_smq_common_2.async.waterfall([ (cb) => { this.ticker.once(events_1.events.DOWN, cb); this.ticker.quit(); }, (cb) => { const multi = this.redisClient.multi(); ConsumerHeartbeat.handleExpiredHeartbeatId(this.consumer.getId(), multi); multi.exec((err) => cb(err)); }, (cb) => this.redisClient.halt(cb), ], cb); } static isExpiredHeartbeat(heartbeat) { const { timestamp: heartbeatTimestamp } = heartbeat; const timestamp = Date.now() - ConsumerHeartbeat.heartbeatTTL; return heartbeatTimestamp > timestamp; } static getConsumersHeartbeats(redisClient, consumerIds, cb) { const keyHeartbeats = redis_keys_1.redisKeys.getMainKeys().keyHeartbeats; redisClient.hmget(keyHeartbeats, consumerIds, (err, reply) => { if (err) cb(err); else if (!reply || reply.length !== consumerIds.length) cb(new redis_smq_common_2.errors.InvalidCallbackReplyError()); else { const r = {}; redis_smq_common_2.async.eachOf(consumerIds, (item, index, done) => { const payload = reply[index]; if (payload) { const consumerHeartbeat = JSON.parse(payload); r[consumerIds[index]] = this.isExpiredHeartbeat(consumerHeartbeat) ? consumerHeartbeat : false; } else r[consumerIds[index]] = false; done(); }, () => cb(null, r)); } }); } static getExpiredHeartbeatIds(redisClient, offset, count, cb) { const { keyHeartbeatConsumerWeight } = redis_keys_1.redisKeys.getMainKeys(); const ts = Date.now() - ConsumerHeartbeat.heartbeatTTL; redisClient.zrangebyscore(keyHeartbeatConsumerWeight, '-inf', ts, offset, count, (err, consumerIds) => { if (err) cb(err); else cb(null, consumerIds !== null && consumerIds !== void 0 ? consumerIds : []); }); } static handleExpiredHeartbeatId(consumerId, multi) { const { keyHeartbeats, keyHeartbeatConsumerWeight } = redis_keys_1.redisKeys.getMainKeys(); const ids = typeof consumerId === 'string' ? [consumerId] : consumerId; ids.forEach((consumerId) => { multi.hdel(keyHeartbeats, consumerId); multi.zrem(keyHeartbeatConsumerWeight, consumerId); }); } } exports.ConsumerHeartbeat = ConsumerHeartbeat; ConsumerHeartbeat.heartbeatTTL = 10 * 1000; //# sourceMappingURL=consumer-heartbeat.js.map