@azure/event-hubs
Version:
Azure Event Hubs SDK for JS.
308 lines (307 loc) • 13.5 kB
JavaScript
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