rocketmq-client-nodejs
Version:
RocketMQ Node.js Client
248 lines • 24.9 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.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Producer = void 0;
const node_assert_1 = __importDefault(require("node:assert"));
const promises_1 = require("node:timers/promises");
const definition_pb_1 = require("../../proto/apache/rocketmq/v2/definition_pb");
const service_pb_1 = require("../../proto/apache/rocketmq/v2/service_pb");
const retry_1 = require("../retry");
const exception_1 = require("../exception");
const client_1 = require("../client");
const message_1 = require("../message");
const PublishingSettings_1 = require("./PublishingSettings");
const PublishingLoadBalancer_1 = require("./PublishingLoadBalancer");
const SendReceipt_1 = require("./SendReceipt");
const Transaction_1 = require("./Transaction");
const util_1 = require("../util");
class Producer extends client_1.BaseClient {
#publishingSettings;
#checker;
#publishingRouteDataCache = new Map();
constructor(options) {
if (!options.topics && options.topic) {
options.topics = Array.isArray(options.topic) ? options.topic : [options.topic];
}
super(options);
// https://rocketmq.apache.org/docs/introduction/03limits/
// Default max number of message sending retries is 3
const retryPolicy = retry_1.ExponentialBackoffRetryPolicy.immediatelyRetryPolicy(options.maxAttempts ?? 3);
this.#publishingSettings = new PublishingSettings_1.PublishingSettings(options.namespace, this.clientId, this.endpoints, retryPolicy, this.requestTimeout, this.topics);
this.#checker = options.checker;
}
get publishingSettings() {
return this.#publishingSettings;
}
beginTransaction() {
(0, node_assert_1.default)(this.#checker, 'Transaction checker should not be null');
return new Transaction_1.Transaction(this);
}
async endTransaction(endpoints, message, messageId, transactionId, resolution) {
const request = new service_pb_1.EndTransactionRequest()
.setMessageId(messageId)
.setTransactionId(transactionId)
.setTopic((0, util_1.createResource)(message.topic).setResourceNamespace(this.namespace))
.setResolution(resolution);
const response = await this.rpcClientManager.endTransaction(endpoints, request, this.requestTimeout);
exception_1.StatusChecker.check(response.getStatus()?.toObject());
}
async onRecoverOrphanedTransactionCommand(endpoints, command) {
const transactionId = command.getTransactionId();
const messagePB = command.getMessage();
const messageId = messagePB.getSystemProperties().getMessageId();
if (!this.#checker) {
this.logger.error('No transaction checker registered, ignore it, messageId=%s, transactionId=%s, endpoints=%s, clientId=%s', messageId, transactionId, endpoints, this.clientId);
return;
}
let messageView;
try {
messageView = new message_1.MessageView(messagePB);
}
catch (err) {
this.logger.error('[Bug] Failed to decode message during orphaned transaction message recovery, messageId=%s, transactionId=%s, endpoints=%s, clientId=%s, error=%s', messageId, transactionId, endpoints, this.clientId, err);
return;
}
try {
const resolution = await this.#checker.check(messageView);
if (resolution === null || resolution === definition_pb_1.TransactionResolution.TRANSACTION_RESOLUTION_UNSPECIFIED) {
return;
}
await this.endTransaction(endpoints, messageView, messageId, transactionId, resolution);
this.logger.info('Recover orphaned transaction message success, transactionId=%s, resolution=%s, messageId=%s, clientId=%s', transactionId, resolution, messageId, this.clientId);
}
catch (err) {
this.logger.error('Exception raised while checking the transaction, messageId=%s, transactionId=%s, endpoints=%s, clientId=%s, error=%s', messageId, transactionId, endpoints, this.clientId, err);
return;
}
}
getSettings() {
return this.#publishingSettings;
}
wrapHeartbeatRequest() {
return new service_pb_1.HeartbeatRequest()
.setClientType(definition_pb_1.ClientType.PRODUCER);
}
wrapNotifyClientTerminationRequest() {
return new service_pb_1.NotifyClientTerminationRequest();
}
async send(message, transaction) {
if (!transaction) {
const sendReceipts = await this.#send([message], false);
return sendReceipts[0];
}
const publishingMessage = transaction.tryAddMessage(message);
const sendReceipts = await this.#send([message], true);
const sendReceipt = sendReceipts[0];
transaction.tryAddReceipt(publishingMessage, sendReceipt);
return sendReceipt;
}
async #send(messages, txEnabled) {
const pubMessages = [];
const topics = new Set();
for (const message of messages) {
pubMessages.push(new message_1.PublishingMessage(message, this.#publishingSettings, txEnabled));
topics.add(message.topic);
}
if (topics.size > 1) {
throw new TypeError(`Messages to send have different topics=${JSON.stringify(topics)}`);
}
const topic = pubMessages[0].topic;
const messageType = pubMessages[0].messageType;
const messageGroup = pubMessages[0].messageGroup;
const messageTypes = new Set(pubMessages.map(m => m.messageType));
if (messageTypes.size > 1) {
throw new TypeError(`Messages to send have different types=${JSON.stringify(messageTypes)}`);
}
// Message group must be same if message type is FIFO, or no need to proceed.
if (messageType === definition_pb_1.MessageType.FIFO) {
const messageGroups = new Set(pubMessages.map(m => m.messageGroup));
if (messageGroups.size > 1) {
throw new TypeError(`FIFO messages to send have message groups, messageGroups=${JSON.stringify(messageGroups)}`);
}
}
// Get publishing topic route.
const loadBalancer = await this.#getPublishingLoadBalancer(topic);
// Prepare the candidate message queue(s) for retry-sending in advance.
const candidates = messageGroup ? [loadBalancer.takeMessageQueueByMessageGroup(messageGroup)] :
this.#takeMessageQueues(loadBalancer);
return await this.#send0(topic, messageType, candidates, pubMessages, 1);
}
#wrapSendMessageRequest(pubMessages, mq) {
const request = new service_pb_1.SendMessageRequest();
for (const pubMessage of pubMessages) {
if (this.namespace) {
request.addMessages(pubMessage.toProtobuf(this.namespace, mq));
}
else {
request.addMessages(pubMessage.toProtobuf('', mq));
}
}
return request;
}
/**
* Isolate specified Endpoints
*/
#isolate(endpoints) {
this.isolated.set(endpoints.facade, endpoints);
}
async #send0(topic, messageType, candidates, messages, attempt) {
// Calculate the current message queue.
const index = (attempt - 1) % candidates.length;
const mq = candidates[index];
const acceptMessageTypes = mq.acceptMessageTypesList;
if (this.#publishingSettings.isValidateMessageType() && !acceptMessageTypes.includes(messageType)) {
throw new TypeError('Current message type not match with ' +
'topic accept message types, topic=' + topic + ', actualMessageType=' + messageType + ', ' +
'acceptMessageTypes=' + JSON.stringify(acceptMessageTypes));
}
const endpoints = mq.broker.endpoints;
const maxAttempts = this.#getRetryPolicy().getMaxAttempts();
const request = this.#wrapSendMessageRequest(messages, mq);
let sendReceipts = [];
try {
const response = await this.rpcClientManager.sendMessage(endpoints, request, this.requestTimeout);
sendReceipts = SendReceipt_1.SendReceipt.processResponseInvocation(mq, response);
}
catch (err) {
const messageIds = messages.map(m => m.messageId);
// Isolate endpoints because of sending failure.
this.#isolate(endpoints);
if (attempt >= maxAttempts) {
// No need more attempts.
this.logger.error('Failed to send message(s) finally, run out of attempt times, maxAttempts=%s, attempt=%s, topic=%s, messageId(s)=%s, endpoints=%s, clientId=%s, error=%s', maxAttempts, attempt, topic, messageIds, endpoints, this.clientId, err);
throw err;
}
// No need more attempts for transactional message.
if (messageType === definition_pb_1.MessageType.TRANSACTION) {
this.logger.error('Failed to send transactional message finally, maxAttempts=%s, attempt=%s, topic=%s, messageId(s)=%s, endpoints=%s, clientId=%s, error=%s', maxAttempts, attempt, topic, messageIds, endpoints, this.clientId, err);
throw err;
}
// Try to do more attempts.
const nextAttempt = 1 + attempt;
// Retry immediately if the request is not throttled.
if (!(err instanceof exception_1.TooManyRequestsException)) {
this.logger.warn('Failed to send message, would attempt to resend right now, maxAttempts=%s, attempt=%s, topic=%s, messageId(s)=%s, endpoints=%s, clientId=%s, error=%s', maxAttempts, attempt, topic, messageIds, endpoints, this.clientId, err);
return this.#send0(topic, messageType, candidates, messages, nextAttempt);
}
const delay = this.#getRetryPolicy().getNextAttemptDelay(nextAttempt);
this.logger.warn('Failed to send message due to too many requests, would attempt to resend after %sms, maxAttempts=%s, attempt=%s, topic=%s, messageId(s)=%s, endpoints=%s, clientId=%s, error=%s', delay, maxAttempts, attempt, topic, messageIds, endpoints, this.clientId, err);
await (0, promises_1.setTimeout)(delay);
return this.#send0(topic, messageType, candidates, messages, nextAttempt);
}
// Resend message(s) successfully.
if (attempt > 1) {
const messageIds = sendReceipts.map(r => r.messageId);
this.logger.info('Resend message successfully, topic=%s, messageId(s)=%j, maxAttempts=%s, attempt=%s, endpoints=%s, clientId=%s', topic, messageIds, maxAttempts, attempt, endpoints, this.clientId);
}
// Send message(s) successfully on first attempt, return directly.
return sendReceipts;
}
async #getPublishingLoadBalancer(topic) {
let loadBalancer = this.#publishingRouteDataCache.get(topic);
if (!loadBalancer) {
const topicRouteData = await this.getRouteData(topic);
loadBalancer = this.#updatePublishingLoadBalancer(topic, topicRouteData);
}
return loadBalancer;
}
#updatePublishingLoadBalancer(topic, topicRouteData) {
let loadBalancer = this.#publishingRouteDataCache.get(topic);
if (loadBalancer) {
loadBalancer = loadBalancer.update(topicRouteData);
}
else {
loadBalancer = new PublishingLoadBalancer_1.PublishingLoadBalancer(topicRouteData);
}
this.#publishingRouteDataCache.set(topic, loadBalancer);
return loadBalancer;
}
/**
* Take message queue(s) from route for message publishing.
*/
#takeMessageQueues(loadBalancer) {
return loadBalancer.takeMessageQueues(this.isolated, this.#getRetryPolicy().getMaxAttempts());
}
#getRetryPolicy() {
return this.#publishingSettings.getRetryPolicy();
}
}
exports.Producer = Producer;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUHJvZHVjZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcHJvZHVjZXIvUHJvZHVjZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7Ozs7Ozs7Ozs7Ozs7R0FlRzs7Ozs7O0FBRUgsOERBQWlDO0FBQ2pDLG1EQUFrRDtBQUNsRCxnRkFJc0Q7QUFDdEQsMEVBTW1EO0FBTW5ELG9DQUVrQjtBQUNsQiw0Q0FBdUU7QUFDdkUsc0NBQW9FO0FBQ3BFLHdDQUFxRjtBQUNyRiw2REFBMEQ7QUFFMUQscUVBQWtFO0FBQ2xFLCtDQUE0QztBQUM1QywrQ0FBNEM7QUFDNUMsa0NBQXlDO0FBUXpDLE1BQWEsUUFBUyxTQUFRLG1CQUFVO0lBQ3RDLG1CQUFtQixDQUFxQjtJQUN4QyxRQUFRLENBQXNCO0lBQzlCLHlCQUF5QixHQUFHLElBQUksR0FBRyxFQUFrQyxDQUFDO0lBRXRFLFlBQVksT0FBd0I7UUFDbEMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLElBQUksT0FBTyxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ3JDLE9BQU8sQ0FBQyxNQUFNLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUUsT0FBTyxDQUFDLEtBQUssQ0FBRSxDQUFDO1FBQ3BGLENBQUM7UUFDRCxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDZiwwREFBMEQ7UUFDMUQscURBQXFEO1FBQ3JELE1BQU0sV0FBVyxHQUFHLHFDQUE2QixDQUFDLHNCQUFzQixDQUFDLE9BQU8sQ0FBQyxXQUFXLElBQUksQ0FBQyxDQUFDLENBQUM7UUFDbkcsSUFBSSxDQUFDLG1CQUFtQixHQUFHLElBQUksdUNBQWtCLENBQUMsT0FBTyxDQUFDLFNBQVMsRUFBRSxJQUFJLENBQUMsUUFBUSxFQUFFLElBQUksQ0FBQyxTQUFTLEVBQUUsV0FBVyxFQUM3RyxJ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