UNPKG

redis-smq

Version:

A simple high-performance Redis message queue for Node.js.

411 lines 14 kB
"use strict"; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Message = void 0; const cron_parser_1 = require("cron-parser"); const types_1 = require("../../../types"); const message_state_1 = require("./message-state"); const message_error_1 = require("./errors/message.error"); const direct_exchange_1 = require("../exchange/direct-exchange"); const topic_exchange_1 = require("../exchange/topic-exchange"); const fan_out_exchange_1 = require("../exchange/fan-out-exchange"); const message_exchange_required_error_1 = require("./errors/message-exchange-required.error"); class Message { constructor() { this.ttl = 0; this.retryThreshold = 3; this.retryDelay = 60000; this.consumeTimeout = 0; this.body = null; this.priority = null; this.scheduledCron = null; this.scheduledDelay = null; this.scheduledRepeatPeriod = null; this.scheduledRepeat = 0; this.messageState = null; this.exchange = null; this.createdAt = Date.now(); const { consumeTimeout, retryDelay, ttl, retryThreshold } = Message.defaultConsumeOptions; this.setConsumeTimeout(consumeTimeout); this.setRetryDelay(retryDelay); this.setTTL(ttl); this.setRetryThreshold(retryThreshold); } getMessageState() { return this.messageState; } getRequiredMessageState() { if (!this.messageState) { throw new message_error_1.MessageError(`Expected an instance of MessageState. Probably the message has not yet been published`); } return this.messageState; } setMessageState(m) { this.messageState = m; return this; } getSetMessageState() { if (!this.messageState) { const m = new message_state_1.MessageState(); if (this.scheduledDelay) m.setNextScheduledDelay(this.scheduledDelay); this.setMessageState(m); return m; } return this.messageState; } getPublishedAt() { if (this.messageState) { return this.messageState.getPublishedAt(); } return null; } getScheduledAt() { if (this.messageState) { return this.messageState.getScheduledAt(); } return null; } getId() { if (this.messageState) { return this.messageState.getId(); } return null; } getRequiredId() { if (!this.messageState) { throw new message_error_1.MessageError(`Message has not yet been published`); } return this.messageState.getId(); } getSetExpired() { return this.getRequiredMessageState().getSetExpired(this.getTTL(), this.getCreatedAt()); } setExchange(exchange) { this.exchange = exchange; return this; } setScheduledRepeatPeriod(period) { const value = Number(period); if (isNaN(value) || value < 0) { throw new message_error_1.MessageError('Expected a positive integer value in milliseconds'); } this.scheduledRepeatPeriod = value; return this; } setScheduledDelay(delay) { const value = Number(delay); if (isNaN(value) || value < 0) { throw new message_error_1.MessageError('Expected a positive integer value in milliseconds'); } this.scheduledDelay = value; return this; } setScheduledCRON(cron) { (0, cron_parser_1.parseExpression)(cron); this.scheduledCron = cron; return this; } setScheduledRepeat(repeat) { const value = Number(repeat); if (isNaN(value) || value < 0) { throw new message_error_1.MessageError('Expected a positive integer value >= 0'); } this.scheduledRepeat = value; return this; } setTTL(ttl) { this.ttl = Message.validateTTL(ttl); return this; } setConsumeTimeout(timeout) { this.consumeTimeout = Message.validateConsumeTimeout(timeout); return this; } setRetryThreshold(threshold) { this.retryThreshold = Message.validateRetryThreshold(threshold); return this; } setRetryDelay(delay) { this.retryDelay = Message.validateRetryDelay(delay); return this; } setBody(body) { this.body = body; return this; } setPriority(priority) { if (!Object.values(Message.MessagePriority).includes(priority)) { throw new message_error_1.MessageError('Invalid message priority.'); } this.priority = priority; return this; } setFanOut(bindingKey) { this.exchange = new fan_out_exchange_1.FanOutExchange(bindingKey); return this; } setTopic(topicParams) { this.exchange = new topic_exchange_1.TopicExchange(topicParams); return this; } setQueue(queueParams) { this.exchange = new direct_exchange_1.DirectExchange(queueParams); return this; } setDestinationQueue(queue) { const exchange = this.getRequiredExchange(); exchange.setDestinationQueue(queue); return this; } disablePriority() { this.priority = null; return this; } hasPriority() { return this.priority !== null; } getQueue() { if (this.exchange instanceof direct_exchange_1.DirectExchange) { return this.exchange.getBindingParams(); } return null; } getTopic() { if (this.exchange instanceof topic_exchange_1.TopicExchange) { return this.exchange.getBindingParams(); } return null; } getFanOutParams() { if (this.exchange instanceof fan_out_exchange_1.FanOutExchange) { return this.exchange.getBindingParams(); } return null; } getDestinationQueue() { const exchange = this.getRequiredExchange(); return exchange.getRequiredDestinationQueue(); } getPriority() { return this.priority; } getBody() { return this.body; } getTTL() { return this.ttl; } getRetryThreshold() { return this.retryThreshold; } getRetryDelay() { return this.retryDelay; } getConsumeTimeout() { return this.consumeTimeout; } getCreatedAt() { return this.createdAt; } getScheduledRepeat() { return this.scheduledRepeat; } getScheduledRepeatPeriod() { return this.scheduledRepeatPeriod; } getScheduledCRON() { return this.scheduledCron; } getMessageScheduledDelay() { return this.scheduledDelay; } hasNextDelay() { if (this.messageState) { return this.messageState.hasDelay(); } return !!this.getMessageScheduledDelay(); } getNextScheduledTimestamp() { if (this.isSchedulable()) { const messageState = this.getRequiredMessageState(); const delay = messageState.getSetNextDelay(); if (delay) { return Date.now() + delay; } const msgScheduledCron = this.getScheduledCRON(); const cronTimestamp = msgScheduledCron ? (0, cron_parser_1.parseExpression)(msgScheduledCron).next().getTime() : 0; const msgScheduledRepeat = this.getScheduledRepeat(); let repeatTimestamp = 0; if (msgScheduledRepeat) { const newCount = messageState.getMessageScheduledRepeatCount() + 1; if (newCount <= msgScheduledRepeat) { const scheduledRepeatPeriod = this.getScheduledRepeatPeriod(); const now = Date.now(); if (scheduledRepeatPeriod) { repeatTimestamp = now + scheduledRepeatPeriod; } else { repeatTimestamp = now; } } } if (repeatTimestamp && cronTimestamp) { if (repeatTimestamp < cronTimestamp && messageState.hasScheduledCronFired()) { messageState.incrMessageScheduledRepeatCount(); return repeatTimestamp; } } if (cronTimestamp) { messageState.resetMessageScheduledRepeatCount(); messageState.setMessageScheduledCronFired(true); return cronTimestamp; } if (repeatTimestamp) { messageState.incrMessageScheduledRepeatCount(); return repeatTimestamp; } } return 0; } getExchange() { return this.exchange; } getRequiredExchange() { if (!this.exchange) { throw new message_exchange_required_error_1.MessageExchangeRequiredError(); } return this.exchange; } toString() { return JSON.stringify(this); } toJSON() { return { createdAt: this.createdAt, ttl: this.ttl, retryThreshold: this.retryThreshold, retryDelay: this.retryDelay, consumeTimeout: this.consumeTimeout, body: this.body, priority: this.priority, scheduledCron: this.scheduledCron, scheduledDelay: this.scheduledDelay, scheduledRepeatPeriod: this.scheduledRepeatPeriod, scheduledRepeat: this.scheduledRepeat, messageState: this.messageState ? this.messageState.toJSON() : null, queue: this.exchange ? this.exchange.getDestinationQueue() : null, exchange: this.exchange ? this.exchange.toJSON() : null, }; } hasRetryThresholdExceeded() { const messageState = this.getMessageState(); if (!messageState) { return false; } const threshold = this.getRetryThreshold(); return messageState.getAttempts() + 1 >= threshold; } isSchedulable() { return this.hasNextDelay() || this.isPeriodic(); } isPeriodic() { return this.getScheduledCRON() !== null || this.getScheduledRepeat() > 0; } static validateRetryDelay(delay) { const value = Number(delay); if (isNaN(value) || value < 0) { throw new message_error_1.MessageError('Expected a positive integer in milliseconds >= 0'); } return value; } static validateTTL(ttl) { const value = Number(ttl); if (isNaN(value) || value < 0) { throw new message_error_1.MessageError('Expected a positive integer value in milliseconds >= 0'); } return value; } static validateConsumeTimeout(timeout) { const value = Number(timeout); if (isNaN(value) || value < 0) { throw new message_error_1.MessageError('Expected a positive integer value in milliseconds >= 0'); } return value; } static validateRetryThreshold(threshold) { const value = Number(threshold); if (isNaN(value) || value < 0) { throw new message_error_1.MessageError('Retry threshold should be a positive integer >= 0'); } return value; } static createFromMessage(message, hardReset = false) { const _a = typeof message === 'string' ? JSON.parse(message) : message.toJSON(), { exchange, messageState, queue } = _a, params = __rest(_a, ["exchange", "messageState", "queue"]); const m = new Message(); Object.assign(m, params); if (messageState) { const meta = new message_state_1.MessageState(); if (!hardReset) Object.assign(meta, messageState); m.setMessageState(meta); } if (exchange) { if (exchange['type'] === types_1.EExchangeType.DIRECT) { m.setExchange(direct_exchange_1.DirectExchange.fromJSON(exchange)); } else if (exchange['type'] === types_1.EExchangeType.FANOUT) { m.setExchange(fan_out_exchange_1.FanOutExchange.fromJSON(exchange)); } else { m.setExchange(topic_exchange_1.TopicExchange.fromJSON(exchange)); } } return m; } static setDefaultConsumeOptions(consumeOptions) { const { ttl = null, retryThreshold = null, retryDelay = null, consumeTimeout = null, } = consumeOptions; if (ttl !== null) Message.defaultConsumeOptions.ttl = Message.validateTTL(ttl); if (retryDelay !== null) Message.defaultConsumeOptions.retryDelay = Message.validateRetryDelay(retryDelay); if (retryThreshold !== null) Message.defaultConsumeOptions.retryThreshold = Message.validateRetryThreshold(retryThreshold); if (consumeTimeout !== null) Message.defaultConsumeOptions.consumeTimeout = Message.validateConsumeTimeout(consumeTimeout); } } exports.Message = Message; Message.MessagePriority = { LOWEST: 7, VERY_LOW: 6, LOW: 5, NORMAL: 4, ABOVE_NORMAL: 3, HIGH: 2, VERY_HIGH: 1, HIGHEST: 0, }; Message.defaultConsumeOptions = { ttl: 0, retryThreshold: 3, retryDelay: 60000, consumeTimeout: 0, }; //# sourceMappingURL=message.js.map