redis-smq
Version:
A high-performance, reliable, and scalable message queue for Node.js.
160 lines • 7.75 kB
JavaScript
import { ERedisScriptName } from '../../common/redis/scripts.js';
import { redisKeys } from '../../common/redis/redis-keys/redis-keys.js';
import { EMessageProperty, EMessagePropertyStatus, } from '../../message/index.js';
import { EQueueOperationalState, EQueueProperty, EQueueType, } from '../../queue-manager/index.js';
import { ConsumerGroupNotFoundError, InvalidQueueStateError, InvalidQueueTypeError, MessageAlreadyExistsError, MessagePriorityRequiredError, PriorityQueuingNotEnabledError, QueueLockedError, QueueNotFoundError, QueueStoppedError, UnexpectedScriptReplyError, } from '../../errors/index.js';
export function _publishMessage(redisClient, message, logger, cb) {
const messageState = message.getMessageState();
const messageId = message.getId();
const destinationQueue = message.getDestinationQueue();
const queueName = `${destinationQueue.name}@${destinationQueue.ns}`;
const consumerGroupId = message.getConsumerGroupId();
logger.debug(`Enqueuing message ${messageId} to queue ${queueName}${consumerGroupId ? ` for consumer group ${consumerGroupId}` : ''}`);
const keys = redisKeys.getQueueKeys(destinationQueue.ns, destinationQueue.name, consumerGroupId);
const { keyMessage } = redisKeys.getMessageKeys(messageId);
const messagePriority = message.producibleMessage.getPriority();
logger.debug(`Message ${messageId} details: priority=${messagePriority ?? 'none'}, queue=${queueName}`);
const scheduledTimestamp = message.getNextScheduledTimestamp();
const messageStatus = scheduledTimestamp
? EMessagePropertyStatus.SCHEDULED
: EMessagePropertyStatus.PENDING;
const queuePropertyValues = [
EQueueProperty.QUEUE_TYPE,
EQueueProperty.MESSAGES_COUNT,
EQueueProperty.PENDING_MESSAGES_COUNT,
EQueueProperty.SCHEDULED_MESSAGES_COUNT,
EQueueType.PRIORITY_QUEUE,
EQueueType.LIFO_QUEUE,
EQueueType.FIFO_QUEUE,
EQueueProperty.OPERATIONAL_STATE,
EQueueProperty.LOCK_ID,
EQueueOperationalState.ACTIVE,
EQueueOperationalState.PAUSED,
EQueueOperationalState.STOPPED,
EQueueOperationalState.LOCKED,
];
const schedulingValues = [
messagePriority ?? '',
scheduledTimestamp,
EMessagePropertyStatus.SCHEDULED,
EMessagePropertyStatus.PENDING,
];
const messagePropertyKeys = [
EMessageProperty.ID,
EMessageProperty.STATUS,
EMessageProperty.MESSAGE,
EMessageProperty.SCHEDULED_AT,
EMessageProperty.PUBLISHED_AT,
EMessageProperty.PROCESSING_STARTED_AT,
EMessageProperty.DEAD_LETTERED_AT,
EMessageProperty.ACKNOWLEDGED_AT,
EMessageProperty.UNACKNOWLEDGED_AT,
EMessageProperty.LAST_UNACKNOWLEDGED_AT,
EMessageProperty.LAST_SCHEDULED_AT,
EMessageProperty.REQUEUED_AT,
EMessageProperty.REQUEUE_COUNT,
EMessageProperty.LAST_REQUEUED_AT,
EMessageProperty.LAST_RETRIED_ATTEMPT_AT,
EMessageProperty.SCHEDULED_CRON_FIRED,
EMessageProperty.ATTEMPTS,
EMessageProperty.SCHEDULED_REPEAT_COUNT,
EMessageProperty.EXPIRED,
EMessageProperty.EFFECTIVE_SCHEDULED_DELAY,
EMessageProperty.SCHEDULED_TIMES,
EMessageProperty.SCHEDULED_MESSAGE_PARENT_ID,
EMessageProperty.REQUEUED_MESSAGE_PARENT_ID,
EMessageProperty.LAST_PROCESSED_AT,
];
const messagePropertyValues = [
messageId,
messageStatus,
JSON.stringify(message.toJSON()),
messageState.getScheduledAt() ?? '',
messageState.getPublishedAt() ?? '',
messageState.getProcessingStartedAt() ?? '',
messageState.getDeadLetteredAt() ?? '',
messageState.getAcknowledgedAt() ?? '',
messageState.getUnacknowledgedAt() ?? '',
messageState.getLastUnacknowledgedAt() ?? '',
messageState.getLastScheduledAt() ?? '',
messageState.getRequeuedAt() ?? '',
messageState.getRequeueCount(),
messageState.getLastRequeuedAt() ?? '',
messageState.getLastRetriedAttemptAt() ?? '',
Number(messageState.isScheduledCronFired()),
messageState.getAttempts(),
messageState.getScheduledRepeatCount(),
Number(messageState.getExpired()),
messageState.getEffectiveScheduledDelay(),
messageState.getScheduledTimes(),
messageState.getScheduledMessageParentId() ?? '',
messageState.getRequeuedMessageParentId() ?? '',
messageState.getLastProcessedAt() ?? '',
];
const scriptArgs = [
...queuePropertyValues,
...schedulingValues,
...messagePropertyKeys,
...messagePropertyValues,
consumerGroupId ?? '',
'',
];
redisClient.runScript(ERedisScriptName.PUBLISH_MESSAGE, [
keys.keyQueueProperties,
keys.keyQueuePriority,
keys.keyQueuePending,
keys.keyQueueScheduled,
keys.keyQueuePublished,
keys.keyQueueConsumerGroups,
keyMessage,
], scriptArgs, (err, reply) => {
if (err) {
logger.error(`Failed to publish message ${messageId}`, err);
return cb(err);
}
switch (reply) {
case 'OK':
logger.debug(`Successfully published message ${messageId} to queue ${queueName}`);
return cb();
case 'QUEUE_NOT_FOUND':
logger.error(`Queue ${queueName} not found for message ${messageId}`);
return cb(new QueueNotFoundError({
metadata: {
queue: destinationQueue,
},
}));
case 'CONSUMER_GROUP_NOT_FOUND':
logger.error(`Consumer group ${consumerGroupId} not found for queue ${queueName}`);
return cb(new ConsumerGroupNotFoundError());
case 'MESSAGE_PRIORITY_REQUIRED':
logger.error(`Priority required for message ${messageId} but not provided`);
return cb(new MessagePriorityRequiredError());
case 'MESSAGE_ALREADY_EXISTS':
logger.error(`A message with ${messageId} already exists`);
return cb(new MessageAlreadyExistsError());
case 'PRIORITY_QUEUING_NOT_ENABLED':
logger.error(`Priority queuing not enabled for queue ${queueName}`);
return cb(new PriorityQueuingNotEnabledError());
case 'UNKNOWN_QUEUE_TYPE':
logger.error(`Unknown queue type for queue ${queueName}`);
return cb(new InvalidQueueTypeError());
case 'QUEUE_STOPPED':
logger.error(`Queue ${queueName} is in STOPPED state, cannot publish message ${messageId}`);
return cb(new QueueStoppedError({ metadata: { queue: destinationQueue } }));
case 'QUEUE_LOCKED':
logger.error(`Queue ${queueName} is in LOCKED state, cannot publish message ${messageId}. Provide a valid lock ID to publish.`);
return cb(new QueueLockedError({ metadata: { queue: destinationQueue } }));
case 'QUEUE_INVALID_STATE':
logger.error(`Queue ${queueName} is in invalid state, cannot publish message ${messageId}`);
return cb(new InvalidQueueStateError({
metadata: {
queue: destinationQueue,
},
}));
default:
logger.error(`Unknown error while publishing message ${messageId}: ${reply}`);
return cb(new UnexpectedScriptReplyError({ metadata: { reply } }));
}
});
}
//# sourceMappingURL=_publish-message.js.map