@team-supercharge/nest-amqp
Version:
AMQP 1.0 module for Nest framework
129 lines (128 loc) • 4.23 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.MessageControl = void 0;
const util_1 = require("../util");
/**
* Class to manage the state of a message transfer and it's status.
*
* @public
*/
class MessageControl {
/**
* @constructor
* @param {EventContext} context Event context received from Rhea related to the message
*/
constructor(context) {
this.context = context;
/**
* Indicate if the message has already been processed.
* If it is, do not process it again.
*
* @private
* @property
*/
this.handled = false;
}
/**
* Use `accept` when message has been handled normally.
*
*
* NOTE: When no explicit `accept` / `reject` / `release` call has been made
* in the callback, message will be automatically accepted.
*/
accept() {
if (this.handled) {
logger.log('message already handled');
return;
}
logger.verbose('accepting message');
this.context.delivery.accept();
this.handleSettlement();
}
/**
* Use `reject` when message was unprocessable. It contained either malformed
* or semantically incorrect data. In other words it can't be successfully
* processed in the future without modifications.
*
* NOTE: With ActiveMQ `reject` will result in the same retry cycle as the
* `release` settlement due to technical limitations. Regardless, please
* always use the appropriate settlement.
*
* @param {string|object} reason reason to reject message
*/
reject(reason) {
if (this.handled) {
logger.log('message already handled');
return;
}
logger.verbose(`rejecting message with reason: ${reason.toString()}`);
// condition and description will not be displayed anywhere
const error = {
condition: 'amqp:precondition-failed',
description: this.getRejectReason(reason),
};
this.context.delivery.reject(error);
this.handleSettlement();
}
/**
* Use release when a temporary problem happened during message handling, e.g.
* could not save record to DB, 3rd party service errored, etc. The message is
* not malformed and theoretically can be processed at a later time without
* modifications.
*
* NOTE: with ActiveMQ `release` will result in the same retry cycle as the
* `reject` settlement due to technical limitations. Regardless, please
* always use the appropriate settlement.
*/
release() {
if (this.handled) {
logger.log('message already handled');
return;
}
logger.verbose('releasing message');
// NOTE: need to be handled this way to trigger retry logic
this.context.delivery.release({
undeliverable_here: true,
delivery_failed: false,
});
this.handleSettlement();
}
/**
* Tells you whether the message has already been processed or not.
*
* @return {boolean} The message has already been processed or not
*/
isHandled() {
return this.handled;
}
/**
* Marking Message as handled, signaling that we are ready for the next message
*
* @private
*/
handleSettlement() {
// need to add a credit after successful handling
this.context.receiver.addCredit(1);
// set as already handled
this.handled = true;
}
/**
* AMQ can only handle string reason messages, need to parse the message
*
* @param {string | object} reason Reason for rejecting the message
* @returns {string} parsed message
*
* @private
*/
getRejectReason(reason) {
try {
return typeof reason !== 'string' ? JSON.stringify(reason) : reason;
}
catch (error) {
logger.error(`could not parse error reason: ${reason}`);
return 'unknown';
}
}
}
exports.MessageControl = MessageControl;
const logger = new util_1.Logger(util_1.getLoggerContext(MessageControl.name));