UNPKG

rocketmq-client-nodejs

Version:
283 lines (261 loc) 10.2 kB
/** * 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. */ import { BaseClientOptions } from '../client'; import { MessageListener } from './MessageListener'; import { OffsetOption } from './OffsetOption'; import { LitePushConsumerImpl } from './LitePushConsumerImpl'; /** * LitePushConsumer interface for consuming messages from lite topics. * * <p>LitePushConsumer is a specialized consumer designed for lightweight scenarios * with reduced metadata and storage overhead. It supports dynamic subscription * management for lite topics.</p> */ export interface LitePushConsumer { /** * Subscribe to a lite topic. * * <p>The subscribeLite() method initiates network requests and performs quota verification, * so it may fail. It's important to check the result of this call to ensure that the * subscription was successfully added. Possible failure scenarios include:</p> * <ul> * <li>Network request errors, which can be retried.</li> * <li>Quota verification failures, indicated by LiteSubscriptionQuotaExceededException. * In this case, evaluate whether the quota is insufficient and promptly unsubscribe * from unused subscriptions using unsubscribeLite() to free up resources.</li> * </ul> * * @param liteTopic - The name of the lite topic to subscribe * @throws ClientException if an error occurs during subscription */ subscribeLite(liteTopic: string): Promise<void>; /** * Subscribe to a lite topic with consumeFromOption to specify the consume from offset. * * @param liteTopic - The name of the lite topic to subscribe * @param offsetOption - The consume from offset option * @throws ClientException if an error occurs during subscription */ subscribeLite(liteTopic: string, offsetOption: OffsetOption): Promise<void>; /** * Unsubscribe from a lite topic. * * @param liteTopic - The name of the lite topic to unsubscribe from * @throws ClientException if an error occurs during unsubscription */ unsubscribeLite(liteTopic: string): Promise<void>; /** * Get the lite topic immutable set. * * @return Lite topic immutable set */ getLiteTopicSet(): Set<string>; /** * Get the load balancing group for the consumer. * * @return Consumer load balancing group */ getConsumerGroup(): string; /** * Close the consumer and release all related resources. * * <p>Once the consumer is closed, <strong>it could not be started once again.</strong> * We maintain an FSM (finite-state machine) to record the different states for each * push consumer.</p> */ close(): Promise<void>; } export interface LitePushConsumerOptions extends BaseClientOptions { consumerGroup: string; bindTopic: string; messageListener: MessageListener; maxCacheMessageCount?: number; maxCacheMessageSizeInBytes?: number; consumptionThreadCount?: number; enableFifoConsumeAccelerator?: boolean; } const CONSUMER_GROUP_PATTERN = /^[a-zA-Z0-9_-]+$/; /** * LitePushConsumer builder class. * * <p>This class provides a fluent API for configuring and creating * lite push consumers with reduced overhead for lightweight scenarios.</p> */ export class LitePushConsumerBuilder { private options: Partial<LitePushConsumerOptions> = {}; /** * Set the bind topic for the lite push consumer. * * @param bindTopic - The parent topic to bind * @return This builder instance * @throws Error if bindTopic is blank */ bindTopic(bindTopic: string): LitePushConsumerBuilder { if (!bindTopic || bindTopic.trim().length === 0) { throw new Error('bindTopic should not be blank'); } this.options.bindTopic = bindTopic; return this; } /** * Set the client configuration. * * @param options - Client configuration options * @return This builder instance * @throws Error if options is null/undefined */ setClientConfiguration(options: BaseClientOptions): LitePushConsumerBuilder { if (!options) { throw new Error('clientConfiguration should not be null'); } Object.assign(this.options, options); return this; } /** * Set the consumer group. * * @param consumerGroup - Consumer group name * @return This builder instance * @throws Error if consumerGroup is null, doesn't match the pattern, or starts with 'GID-' */ setConsumerGroup(consumerGroup: string): LitePushConsumerBuilder { if (!consumerGroup) { throw new Error('consumerGroup should not be null'); } if (!CONSUMER_GROUP_PATTERN.test(consumerGroup)) { throw new Error(`consumerGroup does not match the pattern ${CONSUMER_GROUP_PATTERN.source}`); } this.options.consumerGroup = consumerGroup; return this; } /** * Set the message listener. * * @param messageListener - Message listener implementation * @return This builder instance * @throws Error if messageListener is null/undefined */ setMessageListener(messageListener: MessageListener): LitePushConsumerBuilder { if (!messageListener) { throw new Error('messageListener should not be null'); } this.options.messageListener = messageListener; return this; } /** * Set the maximum cache message count. * * @param maxCacheMessageCount - Maximum number of messages to cache * @return This builder instance * @throws Error if maxCacheMessageCount is not positive */ setMaxCacheMessageCount(maxCacheMessageCount: number): LitePushConsumerBuilder { if (maxCacheMessageCount <= 0) { throw new Error('maxCacheMessageCount should be positive'); } this.options.maxCacheMessageCount = maxCacheMessageCount; return this; } /** * Set the maximum cache message size in bytes. * * @param maxCacheMessageSizeInBytes - Maximum cache size in bytes * @return This builder instance * @throws Error if maxCacheMessageSizeInBytes is not positive */ setMaxCacheMessageSizeInBytes(maxCacheMessageSizeInBytes: number): LitePushConsumerBuilder { if (maxCacheMessageSizeInBytes <= 0) { throw new Error('maxCacheMessageSizeInBytes should be positive'); } this.options.maxCacheMessageSizeInBytes = maxCacheMessageSizeInBytes; return this; } /** * Set the consumption thread count. * * @param consumptionThreadCount - Number of threads for consumption * @return This builder instance * @throws Error if consumptionThreadCount is not positive */ setConsumptionThreadCount(consumptionThreadCount: number): LitePushConsumerBuilder { if (consumptionThreadCount <= 0) { throw new Error('consumptionThreadCount should be positive'); } // Note: Node.js uses a single-threaded event loop model, so this configuration // has no effect on actual consumption concurrency. It is retained solely for // API compatibility with the other clients. Consumption concurrency in Node.js // is naturally managed by the event loop and Promise-based async scheduling. this.options.consumptionThreadCount = consumptionThreadCount; return this; } /** * Set enable fifo consume accelerator. * * <p>If enabled, messages with different messageGroups are consumed in parallel * while messages within the same messageGroup are consumed sequentially.</p> * * @param enableFifoConsumeAccelerator - Whether to enable FIFO consume accelerator * @return This builder instance */ setEnableFifoConsumeAccelerator(enableFifoConsumeAccelerator: boolean): LitePushConsumerBuilder { this.options.enableFifoConsumeAccelerator = enableFifoConsumeAccelerator; return this; } /** * Finalize the build of LitePushConsumer and start. * * <p>This method will block until the push consumer starts successfully. * * <p>Especially, if this method is invoked more than once, different push consumers will be created and started. * * @return Promise resolving to started LitePushConsumer instance * @throws Error if required parameters are not set */ async build(): Promise<LitePushConsumer> { if (!this.options.endpoints) { throw new Error('clientConfiguration has not been set yet'); } if (!this.options.consumerGroup) { throw new Error('consumerGroup has not been set yet'); } if (!this.options.messageListener) { throw new Error('messageListener has not been set yet'); } if (!this.options.bindTopic) { throw new Error('bindTopic has not been set yet'); } // Build LitePushConsumerImpl const options: any = { endpoints: this.options.endpoints, namespace: this.options.namespace ?? '', consumerGroup: this.options.consumerGroup, bindTopic: this.options.bindTopic, messageListener: this.options.messageListener, sslEnabled: this.options.sslEnabled, sessionCredentials: this.options.sessionCredentials, requestTimeout: this.options.requestTimeout, logger: this.options.logger, maxCacheMessageCount: this.options.maxCacheMessageCount, maxCacheMessageSizeInBytes: this.options.maxCacheMessageSizeInBytes, consumptionThreadCount: this.options.consumptionThreadCount, enableFifoConsumeAccelerator: this.options.enableFifoConsumeAccelerator, }; const litePushConsumer = new LitePushConsumerImpl(options); await litePushConsumer.startup(); return litePushConsumer; } }