rocketmq-client-nodejs
Version:
RocketMQ Node.js Client
337 lines • 31.2 kB
JavaScript
"use strict";
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.ProcessQueue = void 0;
const node_crypto_1 = require("node:crypto");
const definition_pb_1 = require("../../proto/apache/rocketmq/v2/definition_pb");
const exception_1 = require("../exception");
const ConsumeResult_1 = require("./ConsumeResult");
const ACK_MESSAGE_FAILURE_BACKOFF_DELAY = 1000;
const CHANGE_INVISIBLE_DURATION_FAILURE_BACKOFF_DELAY = 1000;
const FORWARD_MESSAGE_TO_DLQ_FAILURE_BACKOFF_DELAY = 1000;
const RECEIVING_FLOW_CONTROL_BACKOFF_DELAY = 20;
const RECEIVING_FAILURE_BACKOFF_DELAY = 1000;
const RECEIVING_BACKOFF_DELAY_WHEN_CACHE_IS_FULL = 1000;
class ProcessQueue {
#consumer;
#dropped = false;
#mq;
#filterExpression;
#cachedMessages = [];
#cachedMessagesBytes = 0;
#activityTime = Date.now();
#cacheFullTime = 0;
#aborted = false;
constructor(consumer, mq, filterExpression) {
this.#consumer = consumer;
this.#mq = mq;
this.#filterExpression = filterExpression;
}
getMessageQueue() {
return this.#mq;
}
drop() {
this.#dropped = true;
}
expired() {
const longPollingTimeout = this.#consumer.getPushConsumerSettings().getLongPollingTimeout();
const requestTimeout = this.#consumer.requestTimeoutValue;
const maxIdleDuration = (longPollingTimeout + requestTimeout) * 3;
const idleDuration = Date.now() - this.#activityTime;
if (idleDuration < maxIdleDuration) {
return false;
}
const afterCacheFullDuration = Date.now() - this.#cacheFullTime;
if (afterCacheFullDuration < maxIdleDuration) {
return false;
}
return true;
}
cacheMessages(messageList) {
if (!messageList || messageList.length === 0) {
return;
}
for (const messageView of messageList) {
this.#cachedMessages.push(messageView);
this.#cachedMessagesBytes += messageView.body.length;
}
}
#getReceptionBatchSize() {
const bufferSize = Math.max(this.#consumer.cacheMessageCountThresholdPerQueue() - this.cachedMessagesCount(), 1);
return Math.min(bufferSize, this.#consumer.getPushConsumerSettings().getReceiveBatchSize());
}
fetchMessageImmediately() {
this.#consumer.logger?.info('ProcessQueue.fetchMessageImmediately called, mq=%s@%s@%d', this.#mq.topic.name, this.#mq.broker.name, this.#mq.queueId);
this.#receiveMessageImmediately();
}
onReceiveMessageException(t, attemptId) {
const delay = t instanceof exception_1.TooManyRequestsException
? RECEIVING_FLOW_CONTROL_BACKOFF_DELAY
: RECEIVING_FAILURE_BACKOFF_DELAY;
this.#receiveMessageLater(delay, attemptId);
}
#receiveMessageLater(delay, attemptId) {
if (this.#aborted)
return;
setTimeout(() => {
if (this.#aborted)
return;
this.#receiveMessage(attemptId);
}, delay);
}
#generateAttemptId() {
return (0, node_crypto_1.randomUUID)();
}
receiveMessage(attemptId) {
this.#receiveMessage(attemptId);
}
#receiveMessage(attemptId) {
if (this.#dropped) {
return;
}
if (this.#isCacheFull()) {
this.#receiveMessageLater(RECEIVING_BACKOFF_DELAY_WHEN_CACHE_IS_FULL, attemptId);
return;
}
this.#receiveMessageImmediately(attemptId);
}
#receiveMessageImmediately(attemptId) {
if (this.#aborted)
return;
attemptId = attemptId ?? this.#generateAttemptId();
try {
const batchSize = this.#getReceptionBatchSize();
const longPollingTimeout = this.#consumer.getPushConsumerSettings().getLongPollingTimeout();
const request = this.#consumer.wrapPushReceiveMessageRequest(batchSize, this.#mq, this.#filterExpression, longPollingTimeout, attemptId);
this.#activityTime = Date.now();
this.#consumer.logger?.debug?.('Start to receive message, mq=%s@%s@%d, batchSize=%d, attemptId=%s', this.#mq.topic.name, this.#mq.broker.name, this.#mq.queueId, batchSize, attemptId);
this.#consumer.receiveMessage(request, this.#mq, longPollingTimeout)
.then(messages => {
if (messages.length > 0) {
this.#consumer.logger?.debug?.('Received messages, count=%d, mq=%s@%s@%d', messages.length, this.#mq.topic.name, this.#mq.broker.name, this.#mq.queueId);
}
this.#onReceiveMessageResult(messages);
})
.catch(err => {
this.#consumer.logger?.error('Failed to receive message, mq=%s@%s@%d, error=%s', this.#mq.topic.name, this.#mq.broker.name, this.#mq.queueId, err);
this.onReceiveMessageException(err, attemptId);
});
}
catch (err) {
this.#consumer.logger?.error('Exception in receiveMessage, mq=%s@%s@%d, error=%s', this.#mq.topic.name, this.#mq.broker.name, this.#mq.queueId, err);
this.onReceiveMessageException(err, attemptId);
}
}
#onReceiveMessageResult(messages) {
if (messages.length > 0) {
this.cacheMessages(messages);
this.#consumer.getConsumeService().consume(this, messages);
}
this.#receiveMessage();
}
#isCacheFull() {
const cacheMessageCountThreshold = this.#consumer.cacheMessageCountThresholdPerQueue();
const actualCount = this.cachedMessagesCount();
if (cacheMessageCountThreshold <= actualCount) {
this.#cacheFullTime = Date.now();
return true;
}
const cacheMessageBytesThreshold = this.#consumer.cacheMessageBytesThresholdPerQueue();
if (cacheMessageBytesThreshold <= this.#cachedMessagesBytes) {
this.#cacheFullTime = Date.now();
return true;
}
return false;
}
eraseMessage(messageView, consumeResult) {
if (!messageView) {
return;
}
consumeResult = this.#convertSuspendResultIfNeeded(consumeResult);
this.#statsConsumptionResult(consumeResult);
const task = consumeResult === ConsumeResult_1.ConsumeResult.SUCCESS
? this.#ackMessage(messageView)
: this.#nackMessage(messageView);
task.finally(() => {
this.#evictCache(messageView);
});
}
async #ackMessage(messageView, attempt = 1) {
try {
const endpoints = messageView.endpoints;
const response = await this.#consumer.ackMessageViaRpc(endpoints, this.#consumer.wrapAckMessageRequest(messageView), this.#consumer.requestTimeoutValue);
const status = response.getStatus()?.toObject();
if (status?.code === definition_pb_1.Code.INVALID_RECEIPT_HANDLE) {
return; // Forgive to retry
}
if (status?.code !== definition_pb_1.Code.OK) {
await this.#ackMessageLater(messageView, attempt + 1);
}
}
catch {
await this.#ackMessageLater(messageView, attempt + 1);
}
}
async #ackMessageLater(messageView, attempt) {
if (this.#aborted)
return;
await new Promise(resolve => setTimeout(resolve, ACK_MESSAGE_FAILURE_BACKOFF_DELAY));
if (this.#aborted)
return;
await this.#ackMessage(messageView, attempt);
}
async #nackMessage(messageView) {
const retryPolicy = this.#consumer.getRetryPolicy();
const delay = retryPolicy?.getNextAttemptDelay(messageView.deliveryAttempt ?? 1) ?? 0;
await this.#changeInvisibleDuration(messageView, delay);
}
async #changeInvisibleDuration(messageView, duration, attempt = 1) {
try {
const endpoints = messageView.endpoints;
const response = await this.#consumer.changeInvisibleDurationViaRpc(endpoints, this.#consumer.wrapChangeInvisibleDurationRequest(messageView, duration), this.#consumer.requestTimeoutValue);
const status = response.getStatus()?.toObject();
if (status?.code === definition_pb_1.Code.INVALID_RECEIPT_HANDLE) {
return; // Forgive to retry
}
if (status?.code !== definition_pb_1.Code.OK) {
await this.#changeInvisibleDurationLater(messageView, duration, attempt + 1);
}
}
catch {
await this.#changeInvisibleDurationLater(messageView, duration, attempt + 1);
}
}
async #changeInvisibleDurationLater(messageView, duration, attempt) {
if (this.#aborted)
return;
await new Promise(resolve => setTimeout(resolve, CHANGE_INVISIBLE_DURATION_FAILURE_BACKOFF_DELAY));
if (this.#aborted)
return;
await this.#changeInvisibleDuration(messageView, duration, attempt);
}
async eraseFifoMessage(messageView, consumeResult) {
if (!messageView) {
return;
}
consumeResult = this.#convertSuspendResultIfNeeded(consumeResult);
this.#statsConsumptionResult(consumeResult);
const retryPolicy = this.#consumer.getRetryPolicy();
const maxAttempts = retryPolicy?.getMaxAttempts() ?? 1;
const attempt = messageView.deliveryAttempt ?? 1;
const messageId = messageView.messageId;
const clientId = this.#consumer.clientId;
if (consumeResult === ConsumeResult_1.ConsumeResult.FAILURE && attempt < maxAttempts) {
const nextAttemptDelay = retryPolicy?.getNextAttemptDelay(attempt) ?? 0;
// Increment delivery attempt before redelivering
messageView.incrementAndGetDeliveryAttempt();
this.#consumer.logger?.debug('Prepare to redeliver the fifo message because of the consumption failure, maxAttempts=%d, '
+ 'attempt=%d, mq=%s, messageId=%s, nextAttemptDelay=%d, clientId=%s', maxAttempts, messageView.deliveryAttempt, this.#mq, messageId, nextAttemptDelay, clientId);
// Redeliver the fifo message
const result = await this.#consumer.getConsumeService().consumeMessage(messageView, nextAttemptDelay);
await this.eraseFifoMessage(messageView, result);
return;
}
if (consumeResult === ConsumeResult_1.ConsumeResult.SUCCESS) {
await this.#ackMessage(messageView);
}
else if (consumeResult instanceof ConsumeResult_1.ConsumeResultSuspend) {
const suspendTimeMs = consumeResult.suspendTimeMs;
this.#consumer.logger?.info('Suspend consumption, consumerGroup=%s, topic=%s, liteTopic=%s, messageId=%s, result=%s', this.#consumer.getConsumerGroup(), messageView.topic, messageView.liteTopic ?? '', messageId, consumeResult);
await this.#changeInvisibleDuration(messageView, suspendTimeMs);
}
else {
this.#consumer.logger?.info('Failed to consume fifo message finally, run out of attempt times, maxAttempts=%d, attempt=%d, '
+ 'mq=%s, messageId=%s, clientId=%s', maxAttempts, attempt, this.#mq, messageId, clientId);
await this.#forwardToDeadLetterQueue(messageView);
}
this.#evictCache(messageView);
}
async #forwardToDeadLetterQueue(messageView, attempt = 1) {
try {
const endpoints = messageView.endpoints;
const response = await this.#consumer.forwardMessageToDeadLetterQueueViaRpc(endpoints, this.#consumer.wrapForwardMessageToDeadLetterQueueRequest(messageView), this.#consumer.requestTimeoutValue);
const status = response.getStatus();
if (!status) {
throw new Error('Missing status in forward to dead letter queue response');
}
const statusObj = status.toObject();
if (statusObj.code !== definition_pb_1.Code.OK) {
await this.#forwardToDeadLetterQueueLater(messageView, attempt + 1);
}
}
catch (err) {
if (err.message === 'Missing status in forward to dead letter queue response') {
throw err; // Re-throw critical error
}
await this.#forwardToDeadLetterQueueLater(messageView, attempt + 1);
}
}
async #forwardToDeadLetterQueueLater(messageView, attempt) {
if (this.#aborted)
return;
await new Promise(resolve => setTimeout(resolve, FORWARD_MESSAGE_TO_DLQ_FAILURE_BACKOFF_DELAY));
if (this.#aborted)
return;
await this.#forwardToDeadLetterQueue(messageView, attempt);
}
discardMessage(messageView) {
this.#nackMessage(messageView).finally(() => {
this.#evictCache(messageView);
});
}
discardFifoMessage(messageView) {
this.#forwardToDeadLetterQueue(messageView).finally(() => {
this.#evictCache(messageView);
});
}
#evictCache(messageView) {
const index = this.#cachedMessages.indexOf(messageView);
if (index !== -1) {
this.#cachedMessages.splice(index, 1);
this.#cachedMessagesBytes -= messageView.body.length;
}
}
#convertSuspendResultIfNeeded(consumeResult) {
if (consumeResult instanceof ConsumeResult_1.ConsumeResultSuspend) {
if (!this.#consumer.isLiteConsumer?.()) {
this.#consumer.logger?.warn('Only LitePushConsumer support ConsumeResultSuspend! Convert to ConsumeResult.FAILURE, '
+ 'consumerGroup=%s, consumerType=%s', this.#consumer.getConsumerGroup(), this.#consumer.constructor.name);
return ConsumeResult_1.ConsumeResult.FAILURE;
}
}
return consumeResult;
}
#statsConsumptionResult(consumeResult) {
if (consumeResult === ConsumeResult_1.ConsumeResult.SUCCESS) {
this.#consumer.incrementConsumptionOkQuantity();
return;
}
this.#consumer.incrementConsumptionErrorQuantity();
}
cachedMessagesCount() {
return this.#cachedMessages.length;
}
cachedMessageBytes() {
return this.#cachedMessagesBytes;
}
abort() {
this.#aborted = true;
}
}
exports.ProcessQueue = ProcessQueue;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUHJvY2Vzc1F1ZXVlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbnN1bWVyL1Byb2Nlc3NRdWV1ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7Ozs7Ozs7Ozs7OztHQWVHOzs7QUFFSCw2Q0FBeUM7QUFDekMsZ0ZBQW9FO0FBR3BFLDRDQUF3RDtBQUN4RCxtREFBc0U7QUFJdEUsTUFBTSxpQ0FBaUMsR0FBRyxJQUFJLENBQUM7QUFDL0MsTUFBTSwrQ0FBK0MsR0FBRyxJQUFJLENBQUM7QUFDN0QsTUFBTSw0Q0FBNEMsR0FBRyxJQUFJLENBQUM7QUFFMUQsTUFBTSxvQ0FBb0MsR0FBRyxFQUFFLENBQUM7QUFDaEQsTUFBTSwrQkFBK0IsR0FBRyxJQUFJLENBQUM7QUFDN0MsTUFBTSwwQ0FBMEMsR0FBRyxJQUFJLENBQUM7QUFFeEQsTUFBYSxZQUFZO0lBQ2QsU0FBUyxDQUFlO0lBQ2pDLFFBQVEsR0FBRyxLQUFLLENBQUM7SUFDUixHQUFHLENBQWU7SUFDbEIsaUJBQWlCLENBQW1CO0lBQ3BDLGVBQWUsR0FBa0IsRUFBRSxDQUFDO0lBQzdDLG9CQUFvQixHQUFHLENBQUMsQ0FBQztJQUN6QixhQUFhLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO0lBQzNCLGNBQWMsR0FBRyxDQUFDLENBQUM7SUFDbkIsUUFBUSxHQUFHLEtBQUssQ0FBQztJQUVqQixZQUFZLFFBQXNCLEVBQUUsRUFBZ0IsRUFBRSxnQkFBa0M7UUFDdEYsSUFBSSxDQUFDLFNBQVMsR0FBRyxRQUFRLENBQUM7UUFDMUIsSUFBSSxDQUFDLEdBQUcsR0FBRyxFQUFFLENBQUM7UUFDZCxJQUFJLENBQUMsaUJBQWlCLEdBQUcsZ0JBQWdCLENBQUM7SUFDNUMsQ0FBQztJQUVELGVBQWU7UUFDYixPQUFPLElBQUksQ0FBQyxHQUFHLENBQUM7SUFDbEIsQ0FBQztJQUVELElBQUk7UUFDRixJQUFJLENBQUMsUUFBUSxHQUFHLElBQUksQ0FBQztJ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