redis-smq
Version:
A high-performance, reliable, and scalable message queue for Node.js.
95 lines • 3.81 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MessageAcknowledger = void 0;
const redis_smq_common_1 = require("redis-smq-common");
const _execute_acknowledgement_script_js_1 = require("./_/_execute-acknowledgement-script.js");
class MessageAcknowledger extends redis_smq_common_1.Runnable {
constructor(queue, consumerId, logger, consumerOptions) {
super();
this.pending = [];
this.timer = null;
this.pendingCallbacks = [];
this.queue = queue;
this.consumerId = consumerId;
this.logger = logger.createLogger(this.constructor.name);
const { enabled, batchTimeoutMs, batchSize } = consumerOptions.batchAcks;
this.useBatchAcks = enabled;
this.batchSize = batchSize;
this.batchTimeoutMs = batchTimeoutMs;
}
add(message) {
const messageId = message.getId();
if (!this.isOperational()) {
this.logger.warn(`Rejecting message ${messageId} - MessageAcknowledger is not operational`);
return;
}
if (!this.useBatchAcks) {
const messages = [message];
(0, _execute_acknowledgement_script_js_1._executeAcknowledgementScript)(this.queue, this.consumerId, messages, (err, result) => this.handleAcknowledgementResult(err, result, messages));
return;
}
this.pending.push(message);
this.logger.debug(`Queued message ${messageId} for batch. Queue size: ${this.pending.length}`);
if (this.pending.length >= this.batchSize) {
this.flush();
}
else if (!this.timer) {
this.timer = setTimeout(() => this.flush(), this.batchTimeoutMs);
}
}
flush(cb) {
if (this.timer) {
clearTimeout(this.timer);
this.timer = null;
}
if (this.pending.length === 0) {
if (cb)
cb();
return;
}
if (cb)
this.pendingCallbacks.push(cb);
const batch = [...this.pending];
this.pending = [];
this.logger.debug(`Flushing batch of ${batch.length} acknowledgments`);
(0, _execute_acknowledgement_script_js_1._executeAcknowledgementScript)(this.queue, this.consumerId, batch, (err, result) => {
this.handleAcknowledgementResult(err, result, batch);
const callbacks = [...this.pendingCallbacks];
this.pendingCallbacks = [];
callbacks.forEach((callback) => callback());
});
}
goingDown() {
return [
(cb) => {
this.logger.info(`Shutting down with ${this.pending.length} pending acknowledgments`);
this.flush(cb);
},
];
}
handleAcknowledgementResult(err, result, messages) {
if (err) {
this.logger.error(`Message acknowledgement failed due to: ${err}`);
this.handleError(err);
return;
}
if (!result) {
this.handleError(new redis_smq_common_1.CallbackEmptyReplyError({
message: `_executeAcknowledgementScript() returned an empty result.`,
}));
return;
}
result.forEach((result, index) => {
const message = messages[index];
const messageId = message.getId();
if (result === 0) {
this.logger.info(`Message ${messageId} was already acknowledged or something else`);
return;
}
this.logger.debug(`Message ${messageId} acknowledged successfully`);
this.emit('messageAcknowledger.messageAcknowledged', message);
});
}
}
exports.MessageAcknowledger = MessageAcknowledger;
//# sourceMappingURL=message-acknowledger.js.map