redis-smq
Version:
A simple high-performance Redis message queue for Node.js.
134 lines • 4.55 kB
JavaScript
import * as os from 'os';
import { Runnable, Timer, } from 'redis-smq-common';
import { redisKeys } from '../../../common/redis-keys/redis-keys.js';
import { eventBusPublisher } from './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 {
percentage: ((usageTime(cpuUsageDiff.user + cpuUsageDiff.system) /
hrtime(timestampDiff)) *
100).toFixed(1),
...cpuUsageDiff,
};
}
export class ConsumerHeartbeat extends Runnable {
static heartbeatTTL = 10 * 1000;
timer;
keyConsumerHeartbeat;
consumer;
logger;
redisClient;
constructor(consumer, redisClient, logger, eventBus) {
super();
this.consumer = consumer;
this.logger = logger;
this.redisClient = redisClient;
if (eventBus) {
eventBusPublisher(this, eventBus, this.logger);
}
const { keyConsumerHeartbeat } = redisKeys.getConsumerKeys(consumer.getId());
this.keyConsumerHeartbeat = keyConsumerHeartbeat;
this.timer = new Timer();
this.timer.on('error', (err) => {
this.emit('consumerHeartbeat.error', err);
});
}
getLogger() {
return this.logger;
}
getPayload() {
const timestamp = Date.now();
return {
timestamp,
data: {
ram: {
usage: process.memoryUsage(),
free: os.freemem(),
total: os.totalmem(),
},
cpu: cpuUsage(),
},
};
}
beat() {
const redisClient = this.redisClient.getInstance();
if (redisClient instanceof Error) {
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);
redisClient.set(this.keyConsumerHeartbeat, heartbeatPayloadStr, {
expire: {
mode: 'PX',
value: ConsumerHeartbeat.heartbeatTTL,
},
}, (err) => {
if (err)
this.emit('consumerHeartbeat.error', err);
else {
this.emit('consumerHeartbeat.heartbeat', consumerId, timestamp, heartbeatPayload);
this.timer.setTimeout(() => this.beat(), 1000);
}
});
}
goingUp() {
return super.goingUp().concat([
(cb) => {
const cleanUp = () => {
this.removeListener('consumerHeartbeat.heartbeat', onHeartbeat);
this.removeListener('consumerHeartbeat.error', onError);
};
const onError = (err) => {
cleanUp();
cb(err);
};
const onHeartbeat = () => {
cleanUp();
cb();
};
this.once('consumerHeartbeat.heartbeat', onHeartbeat);
this.once('consumerHeartbeat.error', onError);
this.beat();
},
]);
}
goingDown() {
return [
(cb) => {
this.timer.reset();
const redisClient = this.redisClient.getInstance();
if (redisClient instanceof Error)
return cb();
redisClient.del(this.keyConsumerHeartbeat, () => cb());
},
].concat(super.goingDown());
}
static isConsumerAlive(redisClient, consumerId, cb) {
const { keyConsumerHeartbeat } = redisKeys.getConsumerKeys(consumerId);
redisClient.get(keyConsumerHeartbeat, (err, heartbeat) => {
if (err)
cb(err);
else
cb(null, !!heartbeat);
});
}
}
//# sourceMappingURL=consumer-heartbeat.js.map