UNPKG

@azure/event-hubs

Version:
308 lines (307 loc) • 13.5 kB
var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var eventHubBufferedProducerClient_exports = {}; __export(eventHubBufferedProducerClient_exports, { EventHubBufferedProducerClient: () => EventHubBufferedProducerClient }); module.exports = __toCommonJS(eventHubBufferedProducerClient_exports); var import_eventHubProducerClient = require("./eventHubProducerClient.js"); var import_core_util = require("@azure/core-util"); var import_typeGuards = require("./util/typeGuards.js"); var import_core_amqp = require("@azure/core-amqp"); var import_batchingPartitionChannel = require("./batchingPartitionChannel.js"); var import_partitionAssigner = require("./impl/partitionAssigner.js"); var import_logger = require("./logger.js"); var import_utils = require("./util/utils.js"); class EventHubBufferedProducerClient { /** * Controls the `abortSignal` passed to each `BatchingPartitionChannel`. * Used to signal when a channel should stop waiting for events. */ _abortController = new AbortController(); /** * Indicates whether the client has been explicitly closed. */ _isClosed = false; /** * Handles assigning partitions. */ _partitionAssigner = new import_partitionAssigner.PartitionAssigner(); /** * The known partitionIds that will be used when assigning events to partitions. */ _partitionIds = []; /** * The EventHubProducerClient to use when creating and sending batches to the Event Hub. */ _producer; /** * Mapping of partitionIds to `BatchingPartitionChannels`. * Each `BatchingPartitionChannel` handles buffering events and backpressure independently. */ _partitionChannels = /* @__PURE__ */ new Map(); /** * The options passed by the user when creating the EventHubBufferedProducerClient instance. */ _clientOptions; /** * The interval at which the background management operation should run. */ _backgroundManagementInterval = 1e4; // 10 seconds /** * Indicates whether the background management loop is running. */ _isBackgroundManagementRunning = false; /** * @readonly * The name of the Event Hub instance for which this client is created. */ get eventHubName() { return this._producer.eventHubName; } /** * @readonly * The fully qualified namespace of the Event Hub instance for which this client is created. * This is likely to be similar to <yournamespace>.servicebus.windows.net. */ get fullyQualifiedNamespace() { return this._producer.fullyQualifiedNamespace; } /** * The name used to identify this EventHubBufferedProducerClient. * If not specified or empty, a random unique one will be generated. */ identifier; constructor(fullyQualifiedNamespaceOrConnectionString1, eventHubNameOrOptions2, credentialOrOptions3, options4) { if (typeof eventHubNameOrOptions2 !== "string") { this.identifier = eventHubNameOrOptions2.identifier ?? (0, import_utils.getRandomName)(); this._producer = new import_eventHubProducerClient.EventHubProducerClient(fullyQualifiedNamespaceOrConnectionString1, { ...eventHubNameOrOptions2, identifier: this.identifier }); this._clientOptions = { ...eventHubNameOrOptions2 }; } else if (!(0, import_typeGuards.isCredential)(credentialOrOptions3)) { this.identifier = credentialOrOptions3?.identifier ?? (0, import_utils.getRandomName)(); this._producer = new import_eventHubProducerClient.EventHubProducerClient( fullyQualifiedNamespaceOrConnectionString1, eventHubNameOrOptions2, { ...credentialOrOptions3, identifier: this.identifier } ); this._clientOptions = { ...credentialOrOptions3 }; } else { this.identifier = options4?.identifier ?? (0, import_utils.getRandomName)(); this._producer = new import_eventHubProducerClient.EventHubProducerClient( fullyQualifiedNamespaceOrConnectionString1, eventHubNameOrOptions2, credentialOrOptions3, { ...options4, identifier: this.identifier } ); this._clientOptions = { ...options4 }; } this._producer._enableIdempotentRetries = this._clientOptions.enableIdempotentRetries; } /** * Closes the AMQP connection to the Event Hub instance, * returning a promise that will be resolved when disconnection is completed. * * This will wait for enqueued events to be flushed to the service before closing * the connection. * To close without flushing, set the `flush` option to `false`. * * @param options - The set of options to apply to the operation call. * @returns Promise<void> * @throws Error if the underlying connection encounters an error while closing. */ async close(options = {}) { import_logger.logger.verbose("closing buffered producer client..."); if (!(0, import_core_util.isDefined)(options.flush) || options.flush === true) { await this.flush(options); } this._abortController.abort(); await this._producer.close(); this._isClosed = true; } /** * Enqueues an event into the buffer to be published to the Event Hub. * If there is no capacity in the buffer when this method is invoked, * it will wait for space to become available and ensure that the event * has been enqueued. * * When this call returns, the event has been accepted into the buffer, * but it may not have been published yet. * Publishing will take place at a nondeterministic point in the future as the buffer is processed. * * @param events - An {@link EventData} or `AmqpAnnotatedMessage`. * @param options - A set of options that can be specified to influence the way in which * the event is sent to the associated Event Hub. * - `abortSignal` : A signal used to cancel the enqueueEvent operation. * - `partitionId` : The partition this set of events will be sent to. If set, `partitionKey` can not be set. * - `partitionKey` : A value that is hashed to produce a partition assignment. If set, `partitionId` can not be set. * @returns The total number of events that are currently buffered and waiting to be published, across all partitions. */ async enqueueEvent(event, options = {}) { if (this._isClosed) { throw new Error( `This EventHubBufferedProducerClient has already been closed. Create a new client to enqueue events.` ); } if (!this._partitionIds.length) { await this._updatePartitionIds(); } if (!this._isBackgroundManagementRunning) { this._startPartitionIdsUpdateLoop().catch((e) => { import_logger.logger.error( `The following error occurred during partition ID update loop: ${JSON.stringify( e, void 0, " " )}` ); }); this._isBackgroundManagementRunning = true; } const partitionId = this._partitionAssigner.assignPartition({ partitionId: options.partitionId, partitionKey: options.partitionKey }); const partitionChannel = this._getPartitionChannel(partitionId); await partitionChannel.enqueueEvent(event); return this._getTotalBufferedEventsCount(); } /** * Enqueues events into the buffer to be published to the Event Hub. * If there is no capacity in the buffer when this method is invoked, * it will wait for space to become available and ensure that the events * have been enqueued. * * When this call returns, the events have been accepted into the buffer, * but it may not have been published yet. * Publishing will take place at a nondeterministic point in the future as the buffer is processed. * * @param events - An array of {@link EventData} or `AmqpAnnotatedMessage`. * @param options - A set of options that can be specified to influence the way in which * events are sent to the associated Event Hub. * - `abortSignal` : A signal used to cancel the enqueueEvents operation. * - `partitionId` : The partition this set of events will be sent to. If set, `partitionKey` can not be set. * - `partitionKey` : A value that is hashed to produce a partition assignment. If set, `partitionId` can not be set. * @returns The total number of events that are currently buffered and waiting to be published, across all partitions. */ async enqueueEvents(events, options = {}) { for (const event of events) { await this.enqueueEvent(event, options); } return this._getTotalBufferedEventsCount(); } /** * Attempts to publish all events in the buffer immediately. * This may result in multiple batches being published, * the outcome of each of which will be individually reported by * the `onSendEventsSuccessHandler` and `onSendEventsErrorHandler` handlers. * * @param options - The set of options to apply to the operation call. */ async flush(options = {}) { await Promise.all( Array.from(this._partitionChannels.values()).map((channel) => channel.flush(options)) ); } /** * Provides the Event Hub runtime information. * @param options - The set of options to apply to the operation call. * @returns A promise that resolves with information about the Event Hub instance. * @throws Error if the underlying connection has been closed, create a new EventHubBufferedProducerClient. * @throws AbortError if the operation is cancelled via the abortSignal. */ getEventHubProperties(options = {}) { return this._producer.getEventHubProperties(options); } /** * Provides the id for each partition associated with the Event Hub. * @param options - The set of options to apply to the operation call. * @returns A promise that resolves with an Array of strings representing the id for * each partition associated with the Event Hub. * @throws Error if the underlying connection has been closed, create a new EventHubBufferedProducerClient. * @throws AbortError if the operation is cancelled via the abortSignal. */ getPartitionIds(options = {}) { return this._producer.getPartitionIds(options); } /** * Provides information about the state of the specified partition. * @param partitionId - The id of the partition for which information is required. * @param options - The set of options to apply to the operation call. * @returns A promise that resolves with information about the state of the partition . * @throws Error if the underlying connection has been closed, create a new EventHubBufferedProducerClient. * @throws AbortError if the operation is cancelled via the abortSignal. */ getPartitionProperties(partitionId, options = {}) { return this._producer.getPartitionProperties(partitionId, options); } /** * Gets the `BatchingPartitionChannel` associated with the partitionId. * * If one does not exist, it is created. */ _getPartitionChannel(partitionId) { const partitionChannel = this._partitionChannels.get(partitionId) ?? new import_batchingPartitionChannel.BatchingPartitionChannel({ loopAbortSignal: this._abortController.signal, maxBufferSize: this._clientOptions.maxEventBufferLengthPerPartition || 1500, maxWaitTimeInMs: this._clientOptions.maxWaitTimeInMs || 1e3, onSendEventsErrorHandler: this._clientOptions.onSendEventsErrorHandler, onSendEventsSuccessHandler: this._clientOptions.onSendEventsSuccessHandler, partitionId, producer: this._producer }); this._partitionChannels.set(partitionId, partitionChannel); return partitionChannel; } /** * Returns the total number of buffered events across all partitions. */ _getTotalBufferedEventsCount() { let total = 0; for (const [_, channel] of this._partitionChannels) { total += channel.getCurrentBufferedCount(); } return total; } async _updatePartitionIds() { import_logger.logger.verbose("Checking for partition Id updates..."); const queriedPartitionIds = await this.getPartitionIds(); if (this._partitionIds.length !== queriedPartitionIds.length) { import_logger.logger.verbose("Applying partition Id updates"); this._partitionIds = queriedPartitionIds; this._partitionAssigner.setPartitionIds(this._partitionIds); } } async _startPartitionIdsUpdateLoop() { import_logger.logger.verbose("Starting a background loop to check and apply partition id updates..."); while (!this._abortController.signal.aborted && !this._isClosed) { await (0, import_core_amqp.delay)(this._backgroundManagementInterval); if (!this._isClosed) { await this._updatePartitionIds(); } } } } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { EventHubBufferedProducerClient }); //# sourceMappingURL=eventHubBufferedProducerClient.js.map