rocketmq-client-nodejs
Version:
RocketMQ Node.js Client
156 lines • 13.6 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.SimpleConsumer = void 0;
const definition_pb_1 = require("../../proto/apache/rocketmq/v2/definition_pb");
const service_pb_1 = require("../../proto/apache/rocketmq/v2/service_pb");
const util_1 = require("../util");
const FilterExpression_1 = require("./FilterExpression");
const SimpleSubscriptionSettings_1 = require("./SimpleSubscriptionSettings");
const SubscriptionLoadBalancer_1 = require("./SubscriptionLoadBalancer");
const Consumer_1 = require("./Consumer");
const exception_1 = require("../exception");
const RANDOM_INDEX = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
const DEFAULT_MAX_RETRY_ATTEMPTS = 3;
const RETRY_DELAY_MS = 1000;
class SimpleConsumer extends Consumer_1.Consumer {
#simpleSubscriptionSettings;
#subscriptionExpressions = new Map();
#subscriptionRouteDataCache = new Map();
#awaitDuration;
#maxRetryAttempts;
#topicIndex = RANDOM_INDEX;
constructor(options) {
options.topics = Array.from(options.subscriptions.keys());
super(options);
for (const [topic, filter] of options.subscriptions.entries()) {
if (typeof filter === 'string') {
// filter is tag string
this.#subscriptionExpressions.set(topic, new FilterExpression_1.FilterExpression(filter));
}
else {
this.#subscriptionExpressions.set(topic, filter);
}
}
this.#awaitDuration = options.awaitDuration ?? 30000;
this.#maxRetryAttempts = options.maxRetryAttempts ?? DEFAULT_MAX_RETRY_ATTEMPTS;
this.#simpleSubscriptionSettings = new SimpleSubscriptionSettings_1.SimpleSubscriptionSettings(options.namespace, this.clientId, this.getClientType(), this.endpoints, this.consumerGroup, this.requestTimeout, this.#awaitDuration, this.#subscriptionExpressions);
}
getSettings() {
return this.#simpleSubscriptionSettings;
}
/**
* Get the client type.
*
* @return The client type identifier for simple consumer
*/
getClientType() {
return definition_pb_1.ClientType.SIMPLE_CONSUMER;
}
wrapHeartbeatRequest() {
return new service_pb_1.HeartbeatRequest()
.setClientType(this.getClientType())
.setGroup((0, util_1.createResource)(this.consumerGroup));
}
wrapNotifyClientTerminationRequest() {
return new service_pb_1.NotifyClientTerminationRequest()
.setGroup((0, util_1.createResource)(this.consumerGroup));
}
onTopicRouteDataUpdate(topic, topicRouteData) {
this.#updateSubscriptionLoadBalancer(topic, topicRouteData);
}
#updateSubscriptionLoadBalancer(topic, topicRouteData) {
let subscriptionLoadBalancer = this.#subscriptionRouteDataCache.get(topic);
if (!subscriptionLoadBalancer) {
subscriptionLoadBalancer = new SubscriptionLoadBalancer_1.SubscriptionLoadBalancer(topicRouteData);
}
else {
subscriptionLoadBalancer = subscriptionLoadBalancer.update(topicRouteData);
}
this.#subscriptionRouteDataCache.set(topic, subscriptionLoadBalancer);
return subscriptionLoadBalancer;
}
async #getSubscriptionLoadBalancer(topic) {
let loadBalancer = this.#subscriptionRouteDataCache.get(topic);
if (!loadBalancer) {
const topicRouteData = await this.getRouteData(topic);
loadBalancer = this.#updateSubscriptionLoadBalancer(topic, topicRouteData);
}
return loadBalancer;
}
async subscribe(topic, filterExpression) {
await this.getRouteData(topic);
this.#subscriptionExpressions.set(topic, filterExpression);
}
unsubscribe(topic) {
this.#subscriptionExpressions.delete(topic);
}
async receive(maxMessageNum = 10, invisibleDuration = 15000) {
if (maxMessageNum <= 0) {
throw new Error(`maxMessageNum must be greater than 0, but got ${maxMessageNum}`);
}
const topic = this.#nextTopic();
const filterExpression = this.#subscriptionExpressions.get(topic);
if (!filterExpression) {
throw new Error(`No subscription found for topic=${topic}, please subscribe first`);
}
const loadBalancer = await this.#getSubscriptionLoadBalancer(topic);
const mq = loadBalancer.takeMessageQueue();
const request = this.wrapReceiveMessageRequest(maxMessageNum, mq, filterExpression, invisibleDuration, this.#awaitDuration);
// Retry logic for temporary errors
let lastError;
for (let attempt = 1; attempt <= this.#maxRetryAttempts; attempt++) {
try {
return await this.receiveMessage(request, mq, this.#awaitDuration);
}
catch (err) {
lastError = err;
// Only retry on internal server errors (temporary errors)
if (err instanceof exception_1.InternalErrorException) {
if (attempt < this.#maxRetryAttempts) {
this.logger.warn('Received temporary error from server, will retry after %dms, attempt=%d/%d, topic=%s, clientId=%s, error=%s', RETRY_DELAY_MS, attempt, this.#maxRetryAttempts, topic, this.clientId, err.message);
await new Promise(resolve => setTimeout(resolve, RETRY_DELAY_MS));
continue;
}
}
// For non-retryable errors or max attempts reached, throw immediately
throw err;
}
}
// This should never be reached, but just in case
throw lastError;
}
async ack(message) {
await this.ackMessage(message);
}
async changeInvisibleDuration(message, invisibleDuration) {
const response = await this.invisibleDuration(message, invisibleDuration);
// Refresh receipt handle manually
message.receiptHandle = response;
}
#nextTopic() {
const topics = Array.from(this.#subscriptionExpressions.keys());
if (topics.length === 0) {
throw new Error('No subscriptions available to receive messages');
}
const index = Math.abs(this.#topicIndex++ % topics.length);
return topics[index];
}
}
exports.SimpleConsumer = SimpleConsumer;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2ltcGxlQ29uc3VtZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY29uc3VtZXIvU2ltcGxlQ29uc3VtZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7Ozs7Ozs7Ozs7Ozs7R0FlRzs7O0FBRUgsZ0ZBQTBFO0FBQzFFLDBFQUE2RztBQUc3RyxrQ0FBeUM7QUFDekMseURBQXNEO0FBQ3RELDZFQUEwRTtBQUMxRSx5RUFBc0U7QUFDdEUseUNBQXVEO0FBQ3ZELDRDQUFzRDtBQUV0RCxNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsR0FBRyxNQUFNLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztBQUN6RSxNQUFNLDBCQUEwQixHQUFHLENBQUMsQ0FBQztBQUNyQyxNQUFNLGNBQWMsR0FBRyxJQUFJLENBQUM7QUFzQjVCLE1BQWEsY0FBZSxTQUFRLG1CQUFRO0lBQ2pDLDJCQUEyQixDQUE2QjtJQUN4RCx3QkFBd0IsR0FBRyxJQUFJLEdBQUcsRUFBNEIsQ0FBQztJQUMvRCwyQkFBMkIsR0FBRyxJQUFJLEdBQUcsRUFBb0MsQ0FBQztJQUMxRSxjQUFjLENBQVM7SUFDdkIsaUJBQWlCLENBQVM7SUFDbkMsV0FBVyxHQUFHLFlBQVksQ0FBQztJQUUzQixZQUFZLE9BQThCO1FBQ3hDLE9BQU8sQ0FBQyxNQUFNLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsYUFBYSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7UUFDMUQsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ2YsS0FBSyxNQUFNLENBQUUsS0FBSyxFQUFFLE1BQU0sQ0FBRSxJQUFJLE9BQU8sQ0FBQyxhQUFhLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQztZQUNoRSxJQUFJLE9BQU8sTUFBTSxLQUFLLFFBQVEsRUFBRSxDQUFDO2dCQUMvQix1QkFBdUI7Z0JBQ3ZCLElBQUksQ0FBQyx3QkFBd0Is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