UNPKG

rocketmq-client-nodejs

Version:
337 lines 31.2 kB
"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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