redis-smq
Version:
A high-performance, reliable, and scalable message queue for Node.js.
172 lines • 7.71 kB
JavaScript
import { async, CallbackInvalidReplyError, } from 'redis-smq-common';
import { EQueueOperationalState, EQueueProperty, EQueueType, } from '../../queue-manager/index.js';
import { redisKeys } from '../../common/redis/redis-keys/redis-keys.js';
import { ERedisScriptName } from '../../common/redis/scripts.js';
import { EMessageProperty, EMessagePropertyStatus, } from '../../message/index.js';
import { _getMessage } from './_get-message.js';
import { MessageNotFoundError, QueueLockedError, QueueNotFoundError, UnexpectedScriptReplyError, } from '../../errors/index.js';
export function _deleteMessage(redisClient, messageId, lockId, cb) {
const deleteResponse = {
status: 'MESSAGE_NOT_DELETED',
stats: {
processed: 0,
success: 0,
notFound: 0,
inProcess: 0,
},
};
const ids = Array.isArray(messageId) ? messageId : [messageId];
if (!ids.length) {
deleteResponse.status = 'OK';
return cb(null, deleteResponse);
}
const stats = deleteResponse.stats;
const messages = [];
async.eachOf(ids, (id, _, done) => {
_getMessage(redisClient, id, (err, msg) => {
if (err) {
if (err instanceof MessageNotFoundError) {
stats.notFound += 1;
stats.processed += 1;
return done();
}
return done(err);
}
if (msg)
messages.push(msg);
done();
});
}, (err) => {
if (err)
return cb(err);
if (!messages.length) {
return cb(null, deleteResponse);
}
const messagesByQueueAndGroup = {};
messages.reduce((acc, msg) => {
const queue = msg.getDestinationQueue();
const queueId = `${queue.ns}:${queue.name}`;
if (!acc[queueId]) {
acc[queueId] = {};
}
const consumerGroupId = msg.getConsumerGroupId() ?? '_';
if (!acc[queueId][consumerGroupId]) {
acc[queueId][consumerGroupId] = {
queue,
messages: [],
};
}
acc[queueId][consumerGroupId].messages.push(msg);
return acc;
}, messagesByQueueAndGroup);
async.eachIn(messagesByQueueAndGroup, (groups, _, done) => {
async.eachIn(groups, (item, groupId, done) => {
const { queue, messages: batchMessages } = item;
const consumerGroupId = groupId === '_' ? null : groupId;
const { keyQueueProperties, keyQueuePublished, keyQueuePending, keyQueuePriority, keyQueueScheduled, keyQueueAcknowledged, keyQueueDeadLetter, keyQueueDelayed, keyQueueRequeued, } = redisKeys.getQueueKeys(queue.ns, queue.name, consumerGroupId);
const staticKeys = [
keyQueueProperties,
keyQueuePublished,
keyQueuePending,
keyQueuePriority,
keyQueueScheduled,
keyQueueAcknowledged,
keyQueueDeadLetter,
keyQueueDelayed,
keyQueueRequeued,
];
const staticArgs = [
EQueueProperty.QUEUE_TYPE,
EQueueProperty.MESSAGES_COUNT,
EQueueProperty.ACKNOWLEDGED_MESSAGES_COUNT,
EQueueProperty.DEAD_LETTERED_MESSAGES_COUNT,
EQueueProperty.PENDING_MESSAGES_COUNT,
EQueueProperty.SCHEDULED_MESSAGES_COUNT,
EQueueProperty.DELAYED_MESSAGES_COUNT,
EQueueProperty.REQUEUED_MESSAGES_COUNT,
EQueueType.PRIORITY_QUEUE,
EQueueType.LIFO_QUEUE,
EQueueType.FIFO_QUEUE,
EMessageProperty.STATUS,
EMessagePropertyStatus.PROCESSING,
EMessagePropertyStatus.ACKNOWLEDGED,
EMessagePropertyStatus.PENDING,
EMessagePropertyStatus.SCHEDULED,
EMessagePropertyStatus.DEAD_LETTERED,
EMessagePropertyStatus.UNACK_DELAYING,
EMessagePropertyStatus.UNACK_REQUEUING,
EQueueProperty.OPERATIONAL_STATE,
EQueueOperationalState.LOCKED,
EQueueProperty.LOCK_ID,
lockId ?? '',
];
const dynamicKeys = [];
for (const msg of batchMessages) {
const { keyMessage, keyMessageUnacknowledgementHistory } = redisKeys.getMessageKeys(msg.getId());
dynamicKeys.push(keyMessage, keyMessageUnacknowledgementHistory);
}
const dynamicArgs = batchMessages.map((msg) => msg.getId());
const keys = [...staticKeys, ...dynamicKeys];
const argv = [...staticArgs, ...dynamicArgs];
redisClient.runScript(ERedisScriptName.DELETE_MESSAGE, keys, argv, (err, reply) => {
if (err)
return done(err);
if (reply === 'QUEUE_LOCKED') {
return done(new QueueLockedError({
message: `Cannot delete messages from queue ${queue.name}: Queue is locked`,
metadata: {
queue: queue,
},
}));
}
if (reply === 'INVALID_LOCK') {
return done(new QueueLockedError({
message: `Cannot delete messages from queue ${queue.name}: Invalid lock ID provided`,
metadata: {
queue: queue,
},
}));
}
if (reply === 'QUEUE_NOT_FOUND') {
return done(new QueueNotFoundError({
metadata: {
queue,
},
}));
}
if (reply === 'INVALID_ARGS_ERROR') {
return done(new UnexpectedScriptReplyError({
message: 'Invalid arguments error in DELETE_MESSAGE script',
metadata: {
reply,
},
}));
}
if (!Array.isArray(reply) || reply.length !== 4) {
return done(new CallbackInvalidReplyError());
}
const [processed, success, notFound, inProcess] = reply;
stats.processed += processed;
stats.success += success;
stats.notFound += notFound;
stats.inProcess += inProcess;
done();
});
}, done);
}, (err) => {
if (err)
return cb(err);
if (stats.processed === stats.success && stats.processed > 0) {
deleteResponse.status = 'OK';
}
else if (stats.success > 0) {
deleteResponse.status = 'PARTIAL_SUCCESS';
}
else {
deleteResponse.status = 'MESSAGE_NOT_DELETED';
}
cb(null, deleteResponse);
});
});
}
//# sourceMappingURL=_delete-message.js.map