@azure/event-hubs 5.7.0-beta.1 → 5.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/CHANGELOG.md +1 -9
  2. package/README.md +1 -1
  3. package/dist/index.js +38 -729
  4. package/dist/index.js.map +1 -1
  5. package/dist-esm/src/diagnostics/instrumentEventData.js +15 -33
  6. package/dist-esm/src/diagnostics/instrumentEventData.js.map +1 -1
  7. package/dist-esm/src/diagnostics/tracing.js.map +1 -1
  8. package/dist-esm/src/eventDataBatch.js +17 -6
  9. package/dist-esm/src/eventDataBatch.js.map +1 -1
  10. package/dist-esm/src/eventHubProducerClient.js +11 -2
  11. package/dist-esm/src/eventHubProducerClient.js.map +1 -1
  12. package/dist-esm/src/index.js +0 -1
  13. package/dist-esm/src/index.js.map +1 -1
  14. package/dist-esm/src/util/constants.js +1 -1
  15. package/dist-esm/src/util/constants.js.map +1 -1
  16. package/package.json +15 -19
  17. package/types/3.1/event-hubs.d.ts +2 -287
  18. package/types/latest/event-hubs.d.ts +2 -310
  19. package/types/latest/tsdoc-metadata.json +1 -1
  20. package/dist-esm/src/batchingPartitionChannel.js +0 -241
  21. package/dist-esm/src/batchingPartitionChannel.js.map +0 -1
  22. package/dist-esm/src/eventHubBufferedProducerClient.js +0 -242
  23. package/dist-esm/src/eventHubBufferedProducerClient.js.map +0 -1
  24. package/dist-esm/src/impl/awaitableQueue.js +0 -46
  25. package/dist-esm/src/impl/awaitableQueue.js.map +0 -1
  26. package/dist-esm/src/impl/partitionAssigner.js +0 -54
  27. package/dist-esm/src/impl/partitionAssigner.js.map +0 -1
  28. package/dist-esm/src/impl/patitionKeyToIdMapper.js +0 -106
  29. package/dist-esm/src/impl/patitionKeyToIdMapper.js.map +0 -1
  30. package/dist-esm/src/util/getPromiseParts.js +0 -20
  31. package/dist-esm/src/util/getPromiseParts.js.map +0 -1
@@ -1,8 +1,6 @@
1
1
  /// <reference types="node" />
2
-
3
2
  import { AbortSignalLike } from '@azure/abort-controller';
4
3
  import { AmqpAnnotatedMessage } from '@azure/core-amqp';
5
- import { AzureLogger } from '@azure/logger';
6
4
  import { MessagingError } from '@azure/core-amqp';
7
5
  import { NamedKeyCredential } from '@azure/core-auth';
8
6
  import { OperationTracingOptions } from '@azure/core-tracing';
@@ -15,24 +13,6 @@ import { TokenCredential } from '@azure/core-auth';
15
13
  import { WebSocketImpl } from 'rhea-promise';
16
14
  import { WebSocketOptions } from '@azure/core-amqp';
17
15
 
18
- /**
19
- * Options to configure the `close` method on the `EventHubBufferedProducerClient`.
20
- */
21
- export declare interface BufferedCloseOptions extends OperationOptions {
22
- /**
23
- * When `true`, all buffered events that are pending should be sent before closing.
24
- * When `false`, abandon all buffered events and close immediately.
25
- * Defaults to `true`.
26
- */
27
- flush?: boolean;
28
- }
29
-
30
- /**
31
- * Options to configure the `flush` method on the `EventHubBufferedProducerClient`.
32
- */
33
- export declare interface BufferedFlushOptions extends OperationOptions {
34
- }
35
-
36
16
  /**
37
17
  * A checkpoint is meant to represent the last successfully processed event by the user from a particular
38
18
  * partition of a consumer group in an Event Hub instance.
@@ -188,12 +168,6 @@ export declare interface CreateBatchOptions extends OperationOptions {
188
168
  */
189
169
  export declare const earliestEventPosition: EventPosition;
190
170
 
191
- /**
192
- * Options to configure the `enqueueEvents` method on the `EventHubBufferedProcuerClient`.
193
- */
194
- export declare interface EnqueueEventOptions extends SendBatchOptions {
195
- }
196
-
197
171
  /**
198
172
  * The interface that describes the data to be sent to Event Hub.
199
173
  * Use this as a reference when creating the object to be sent when using the `EventHubProducerClient`.
@@ -284,248 +258,6 @@ export declare interface EventDataBatch {
284
258
  /* Excluded from this release type: _messageSpanContexts */
285
259
  }
286
260
 
287
- /**
288
- * The `EventHubBufferedProducerClient`is used to publish events to a specific Event Hub.
289
- *
290
- * The `EventHubBufferedProducerClient` does not publish events immediately.
291
- * Instead, events are buffered so they can be efficiently batched and published
292
- * when the batch is full or the `maxWaitTimeInMs` has elapsed with no new events
293
- * enqueued.
294
- *
295
- * Depending on the options specified when events are enqueued, they may be
296
- * automatically assigned to a partition, grouped according to the specified partition key,
297
- * or assigned a specifically requested partition.
298
- *
299
- * This model is intended to shift the burden of batch management from callers, at the cost of
300
- * non-deterministic timing, for when events will be published. There are additional trade-offs
301
- * to consider, as well:
302
- * - If the application crashes, events in the buffer will not have been published. To prevent
303
- * data loss, callers are encouraged to track publishing progress using the
304
- * `onSendEventsSuccessHandler` and `onSendEventsErrorHandler` handlers.
305
- * - Events specifying a partition key may be assigned a different partition than those using
306
- * the same key with other producers.
307
- * - In the unlikely event that a partition becomes temporarily unavailable, the
308
- * `EventHubBufferedProducerClient` may take longer to recover than other producers.
309
- *
310
- * In scenarios where it is important to have events published immediately with a deterministic
311
- * outcome, ensure that partition keys are assigned to a partition consistent with other
312
- * publishers, or where maximizing availability is a requirement, using the
313
- * `EventHubProducerClient` is recommended.
314
- */
315
- export declare class EventHubBufferedProducerClient {
316
- /**
317
- * Controls the `abortSignal` passed to each `BatchingPartitionChannel`.
318
- * Used to signal when a channel should stop waiting for events.
319
- */
320
- private _abortController;
321
- /**
322
- * Indicates whether the client has been explicitly closed.
323
- */
324
- private _isClosed;
325
- /**
326
- * Handles assigning partitions.
327
- */
328
- private _partitionAssigner;
329
- /**
330
- * The known partitionIds that will be used when assigning events to partitions.
331
- */
332
- private _partitionIds;
333
- /**
334
- * The EventHubProducerClient to use when creating and sending batches to the Event Hub.
335
- */
336
- private _producer;
337
- /**
338
- * Mapping of partitionIds to `BatchingPartitionChannels`.
339
- * Each `BatchingPartitionChannel` handles buffering events and backpressure independently.
340
- */
341
- private _partitionChannels;
342
- /**
343
- * The options passed by the user when creating the EventHubBufferedProducerClient instance.
344
- */
345
- private _clientOptions;
346
- /**
347
- * @readonly
348
- * The name of the Event Hub instance for which this client is created.
349
- */
350
- get eventHubName(): string;
351
- /**
352
- * @readonly
353
- * The fully qualified namespace of the Event Hub instance for which this client is created.
354
- * This is likely to be similar to <yournamespace>.servicebus.windows.net.
355
- */
356
- get fullyQualifiedNamespace(): string;
357
- /**
358
- * The `EventHubBufferedProducerClient` class is used to send events to an Event Hub.
359
- * Use the `options` parmeter to configure retry policy or proxy settings.
360
- * @param connectionString - The connection string to use for connecting to the Event Hub instance.
361
- * It is expected that the shared key properties and the Event Hub path are contained in this connection string.
362
- * e.g. 'Endpoint=sb://my-servicebus-namespace.servicebus.windows.net/;SharedAccessKeyName=my-SA-name;SharedAccessKey=my-SA-key;EntityPath=my-event-hub-name'.
363
- * @param options - A set of options to apply when configuring the client.
364
- * - `retryOptions` : Configures the retry policy for all the operations on the client.
365
- * For example, `{ "maxRetries": 4 }` or `{ "maxRetries": 4, "retryDelayInMs": 30000 }`.
366
- * - `webSocketOptions`: Configures the channelling of the AMQP connection over Web Sockets.
367
- * - `userAgent` : A string to append to the built in user agent string that is passed to the service.
368
- */
369
- constructor(connectionString: string, options: EventHubBufferedProducerClientOptions);
370
- /**
371
- * The `EventHubBufferedProducerClient` class is used to send events to an Event Hub.
372
- * Use the `options` parmeter to configure retry policy or proxy settings.
373
- * @param connectionString - The connection string to use for connecting to the Event Hubs namespace.
374
- * It is expected that the shared key properties are contained in this connection string, but not the Event Hub path,
375
- * e.g. 'Endpoint=sb://my-servicebus-namespace.servicebus.windows.net/;SharedAccessKeyName=my-SA-name;SharedAccessKey=my-SA-key;'.
376
- * @param eventHubName - The name of the specific Event Hub to connect the client to.
377
- * @param options - A set of options to apply when configuring the client.
378
- * - `retryOptions` : Configures the retry policy for all the operations on the client.
379
- * For example, `{ "maxRetries": 4 }` or `{ "maxRetries": 4, "retryDelayInMs": 30000 }`.
380
- * - `webSocketOptions`: Configures the channelling of the AMQP connection over Web Sockets.
381
- * - `userAgent` : A string to append to the built in user agent string that is passed to the service.
382
- */
383
- constructor(connectionString: string, eventHubName: string, options: EventHubBufferedProducerClientOptions);
384
- /**
385
- * The `EventHubBufferedProducerClient` class is used to send events to an Event Hub.
386
- * Use the `options` parmeter to configure retry policy or proxy settings.
387
- * @param fullyQualifiedNamespace - The full namespace which is likely to be similar to
388
- * <yournamespace>.servicebus.windows.net
389
- * @param eventHubName - The name of the specific Event Hub to connect the client to.
390
- * @param credential - An credential object used by the client to get the token to authenticate the connection
391
- * with the Azure Event Hubs service.
392
- * See &commat;azure/identity for creating credentials that support AAD auth.
393
- * Use the `AzureNamedKeyCredential` from &commat;azure/core-auth if you want to pass in a `SharedAccessKeyName`
394
- * and `SharedAccessKey` without using a connection string. These fields map to the `name` and `key` field respectively
395
- * in `AzureNamedKeyCredential`.
396
- * Use the `AzureSASCredential` from &commat;azure/core-auth if you want to pass in a `SharedAccessSignature`
397
- * without using a connection string. This field maps to `signature` in `AzureSASCredential`.
398
- * @param options - A set of options to apply when configuring the client.
399
- * - `retryOptions` : Configures the retry policy for all the operations on the client.
400
- * For example, `{ "maxRetries": 4 }` or `{ "maxRetries": 4, "retryDelayInMs": 30000 }`.
401
- * - `webSocketOptions`: Configures the channelling of the AMQP connection over Web Sockets.
402
- * - `userAgent` : A string to append to the built in user agent string that is passed to the service.
403
- */
404
- constructor(fullyQualifiedNamespace: string, eventHubName: string, credential: TokenCredential | NamedKeyCredential | SASCredential, options: EventHubBufferedProducerClientOptions);
405
- /**
406
- * Closes the AMQP connection to the Event Hub instance,
407
- * returning a promise that will be resolved when disconnection is completed.
408
- *
409
- * This will wait for enqueued events to be flushed to the service before closing
410
- * the connection.
411
- * To close without flushing, set the `flush` option to `false`.
412
- *
413
- * @param options - The set of options to apply to the operation call.
414
- * @returns Promise<void>
415
- * @throws Error if the underlying connection encounters an error while closing.
416
- */
417
- close(options?: BufferedCloseOptions): Promise<void>;
418
- /**
419
- * Enqueues an event into the buffer to be published to the Event Hub.
420
- * If there is no capacity in the buffer when this method is invoked,
421
- * it will wait for space to become available and ensure that the event
422
- * has been enqueued.
423
- *
424
- * When this call returns, the event has been accepted into the buffer,
425
- * but it may not have been published yet.
426
- * Publishing will take place at a nondeterministic point in the future as the buffer is processed.
427
- *
428
- * @param events - An {@link EventData} or `AmqpAnnotatedMessage`.
429
- * @param options - A set of options that can be specified to influence the way in which
430
- * the event is sent to the associated Event Hub.
431
- * - `abortSignal` : A signal used to cancel the enqueueEvent operation.
432
- * - `partitionId` : The partition this set of events will be sent to. If set, `partitionKey` can not be set.
433
- * - `partitionKey` : A value that is hashed to produce a partition assignment. If set, `partitionId` can not be set.
434
- * @returns The total number of events that are currently buffered and waiting to be published, across all partitions.
435
- */
436
- enqueueEvent(event: EventData | AmqpAnnotatedMessage, options?: EnqueueEventOptions): Promise<number>;
437
- /**
438
- * Enqueues events into the buffer to be published to the Event Hub.
439
- * If there is no capacity in the buffer when this method is invoked,
440
- * it will wait for space to become available and ensure that the events
441
- * have been enqueued.
442
- *
443
- * When this call returns, the events have been accepted into the buffer,
444
- * but it may not have been published yet.
445
- * Publishing will take place at a nondeterministic point in the future as the buffer is processed.
446
- *
447
- * @param events - An array of {@link EventData} or `AmqpAnnotatedMessage`.
448
- * @param options - A set of options that can be specified to influence the way in which
449
- * events are sent to the associated Event Hub.
450
- * - `abortSignal` : A signal used to cancel the enqueueEvents operation.
451
- * - `partitionId` : The partition this set of events will be sent to. If set, `partitionKey` can not be set.
452
- * - `partitionKey` : A value that is hashed to produce a partition assignment. If set, `partitionId` can not be set.
453
- * @returns The total number of events that are currently buffered and waiting to be published, across all partitions.
454
- */
455
- enqueueEvents(events: EventData[] | AmqpAnnotatedMessage[], options?: EnqueueEventOptions): Promise<number>;
456
- /**
457
- * Attempts to publish all events in the buffer immediately.
458
- * This may result in multiple batches being published,
459
- * the outcome of each of which will be individually reported by
460
- * the `onSendEventsSuccessHandler` and `onSendEventsErrorHandler` handlers.
461
- *
462
- * @param options - The set of options to apply to the operation call.
463
- */
464
- flush(options?: BufferedFlushOptions): Promise<void>;
465
- /**
466
- * Provides the Event Hub runtime information.
467
- * @param options - The set of options to apply to the operation call.
468
- * @returns A promise that resolves with information about the Event Hub instance.
469
- * @throws Error if the underlying connection has been closed, create a new EventHubBufferedProducerClient.
470
- * @throws AbortError if the operation is cancelled via the abortSignal.
471
- */
472
- getEventHubProperties(options?: GetEventHubPropertiesOptions): Promise<EventHubProperties>;
473
- /**
474
- * Provides the id for each partition associated with the Event Hub.
475
- * @param options - The set of options to apply to the operation call.
476
- * @returns A promise that resolves with an Array of strings representing the id for
477
- * each partition associated with the Event Hub.
478
- * @throws Error if the underlying connection has been closed, create a new EventHubBufferedProducerClient.
479
- * @throws AbortError if the operation is cancelled via the abortSignal.
480
- */
481
- getPartitionIds(options?: GetPartitionIdsOptions): Promise<Array<string>>;
482
- /**
483
- * Provides information about the state of the specified partition.
484
- * @param partitionId - The id of the partition for which information is required.
485
- * @param options - The set of options to apply to the operation call.
486
- * @returns A promise that resolves with information about the state of the partition .
487
- * @throws Error if the underlying connection has been closed, create a new EventHubBufferedProducerClient.
488
- * @throws AbortError if the operation is cancelled via the abortSignal.
489
- */
490
- getPartitionProperties(partitionId: string, options?: GetPartitionPropertiesOptions): Promise<PartitionProperties>;
491
- /**
492
- * Gets the `BatchingPartitionChannel` associated with the partitionId.
493
- *
494
- * If one does not exist, it is created.
495
- */
496
- private _getPartitionChannel;
497
- /**
498
- * Returns the total number of buffered events across all partitions.
499
- */
500
- private _getTotalBufferedEventsCount;
501
- }
502
-
503
- /**
504
- * Describes the options that can be provided while creating the `EventHubBufferedProducerClient`.
505
- */
506
- export declare interface EventHubBufferedProducerClientOptions extends EventHubClientOptions {
507
- /**
508
- * The total number of events that can be buffered for publishing at a given time for a given partition.
509
- *
510
- * Default: 1500
511
- */
512
- maxEventBufferLengthPerPartition?: number;
513
- /**
514
- * The amount of time to wait for a new event to be enqueued in the buffer before publishing a partially full batch.
515
- *
516
- * Default: 1 second.
517
- */
518
- maxWaitTimeInMs?: number;
519
- /**
520
- * The handler to call once a batch has successfully published.
521
- */
522
- onSendEventsSuccessHandler?: (ctx: OnSendEventsSuccessContext) => Promise<void>;
523
- /**
524
- * The handler to call when a batch fails to publish.
525
- */
526
- onSendEventsErrorHandler: (ctx: OnSendEventsErrorContext) => Promise<void>;
527
- }
528
-
529
261
  /**
530
262
  * Describes the options that can be provided while creating the EventHubClient.
531
263
  * - `userAgent` : A string to append to the built in user agent string that is passed as a connection property
@@ -1281,44 +1013,9 @@ export declare interface LoadBalancingOptions {
1281
1013
  * The `@azure/logger` configuration for this package.
1282
1014
  * This will output logs using the `azure:event-hubs` namespace prefix.
1283
1015
  */
1284
- export declare const logger: AzureLogger;
1285
-
1016
+ export declare const logger: import("@azure/logger").AzureLogger;
1286
1017
  export { MessagingError }
1287
1018
 
1288
- /**
1289
- * Contains the events that were not successfully sent to the Event Hub,
1290
- * the partition they were assigned to, and the error that was encountered while sending.
1291
- */
1292
- export declare interface OnSendEventsErrorContext {
1293
- /**
1294
- * The partition each event was assigned.
1295
- */
1296
- partitionId: string;
1297
- /**
1298
- * The array of {@link EventData} and/or `AmqpAnnotatedMessage` that were not successfully sent to the Event Hub.
1299
- */
1300
- events: Array<EventData | AmqpAnnotatedMessage>;
1301
- /**
1302
- * The error that occurred when sending the associated events to the Event Hub.
1303
- */
1304
- error: Error;
1305
- }
1306
-
1307
- /**
1308
- * Contains the events that were successfully sent to the Event Hub,
1309
- * and the partition they were assigned to.
1310
- */
1311
- export declare interface OnSendEventsSuccessContext {
1312
- /**
1313
- * The partition each event was assigned.
1314
- */
1315
- partitionId: string;
1316
- /**
1317
- * The array of {@link EventData} and/or `AmqpAnnotatedMessage` that were successfully sent to the Event Hub.
1318
- */
1319
- events: Array<EventData | AmqpAnnotatedMessage>;
1320
- }
1321
-
1322
1019
  /**
1323
1020
  * Options for configuring tracing and the abortSignal.
1324
1021
  */
@@ -1539,9 +1236,7 @@ export declare interface ReceivedEventData {
1539
1236
  */
1540
1237
  getRawAmqpMessage(): AmqpAnnotatedMessage;
1541
1238
  }
1542
-
1543
1239
  export { RetryMode }
1544
-
1545
1240
  export { RetryOptions }
1546
1241
 
1547
1242
  /**
@@ -1592,7 +1287,7 @@ export declare interface SubscribeOptions {
1592
1287
  /**
1593
1288
  * Indicates whether or not the consumer should request information on the last enqueued event on its
1594
1289
  * associated partition, and track that information as events are received.
1595
-
1290
+
1596
1291
  * When information about the partition's last enqueued event is being tracked, each event received
1597
1292
  * from the Event Hubs service will carry metadata about the partition that it otherwise would not. This results in a small amount of
1598
1293
  * additional network bandwidth consumption that is generally a favorable trade-off when considered
@@ -1694,7 +1389,6 @@ export declare interface SubscriptionEventHandlers {
1694
1389
  */
1695
1390
  processClose?: ProcessCloseHandler;
1696
1391
  }
1697
-
1698
1392
  export { TokenCredential }
1699
1393
 
1700
1394
  /**
@@ -1710,9 +1404,7 @@ export declare interface TryAddOptions {
1710
1404
  */
1711
1405
  parentSpan?: Span | SpanContext;
1712
1406
  }
1713
-
1714
1407
  export { WebSocketImpl }
1715
-
1716
1408
  export { WebSocketOptions }
1717
1409
 
1718
1410
  export { }
@@ -5,7 +5,7 @@
5
5
  "toolPackages": [
6
6
  {
7
7
  "packageName": "@microsoft/api-extractor",
8
- "packageVersion": "7.18.19"
8
+ "packageVersion": "7.7.11"
9
9
  }
10
10
  ]
11
11
  }
@@ -1,241 +0,0 @@
1
- // Copyright (c) Microsoft Corporation.
2
- // Licensed under the MIT license.
3
- import { delay } from "@azure/core-amqp";
4
- import { AwaitableQueue } from "./impl/awaitableQueue";
5
- import { isDefined, isObjectWithProperties } from "./util/typeGuards";
6
- import { getPromiseParts } from "./util/getPromiseParts";
7
- import { logger } from "./log";
8
- /**
9
- * The `BatchingPartitionChannel` is responsible for accepting enqueued events
10
- * and optimally batching and sending them to an Event Hub.
11
- * @internal
12
- */
13
- export class BatchingPartitionChannel {
14
- constructor({ loopAbortSignal, maxBufferSize, maxWaitTimeInMs, onSendEventsErrorHandler, onSendEventsSuccessHandler, partitionId, producer }) {
15
- this._eventQueue = new AwaitableQueue();
16
- this._batchedEvents = [];
17
- this._bufferCount = 0;
18
- this._readyQueue = [];
19
- this._flushState = {
20
- isFlushing: false
21
- };
22
- this._isRunning = false;
23
- this._lastBatchCreationTime = 0;
24
- this._loopAbortSignal = loopAbortSignal;
25
- this._maxBufferSize = maxBufferSize;
26
- this._maxWaitTimeInMs = maxWaitTimeInMs;
27
- this._onSendEventsErrorHandler = onSendEventsErrorHandler;
28
- this._onSendEventsSuccessHandler = onSendEventsSuccessHandler;
29
- this._partitionId = partitionId;
30
- this._producer = producer;
31
- }
32
- getCurrentBufferedCount() {
33
- return this._bufferCount;
34
- }
35
- async enqueueEvent(event) {
36
- await this._ready();
37
- this._eventQueue.push(event);
38
- this._bufferCount++;
39
- if (!this._isRunning) {
40
- this._isRunning = true;
41
- this._startPublishLoop().catch((e) => {
42
- logger.error(`The following error occured during batch creation or sending: ${JSON.stringify(e, undefined, " ")}`);
43
- });
44
- }
45
- }
46
- /**
47
- * Sets the flush state so that no new events can be enqueued until
48
- * all the currently buffered events are sent to the Event Hub.
49
- *
50
- * Returns a promise that resolves once flushing is complete.
51
- */
52
- async flush(_options = {}) {
53
- const state = this._flushState;
54
- if (state.isFlushing) {
55
- return state.currentPromise;
56
- }
57
- if (this.getCurrentBufferedCount() === 0) {
58
- return Promise.resolve();
59
- }
60
- const { promise, resolve } = getPromiseParts();
61
- this._flushState = { isFlushing: true, currentPromise: promise, resolve };
62
- return promise;
63
- }
64
- /**
65
- * Returns a promise that resolves once there is room for events to be added
66
- * to the buffer.
67
- */
68
- _ready() {
69
- const currentBufferedCount = this.getCurrentBufferedCount();
70
- // If the buffer isn't full and we don't have any pending `ready()` calls,
71
- // then it's safe to return right away.
72
- if (currentBufferedCount < this._maxBufferSize &&
73
- !this._readyQueue.length &&
74
- !this._flushState.isFlushing) {
75
- return Promise.resolve();
76
- }
77
- const { promise: readyPromise, reject, resolve } = getPromiseParts();
78
- this._readyQueue.push({ resolve, reject });
79
- return readyPromise;
80
- }
81
- /**
82
- * Starts the loop that creates batches and sends them to the Event Hub.
83
- *
84
- * The loop will run until the `_loopAbortSignal` is aborted.
85
- */
86
- async _startPublishLoop() {
87
- let batch;
88
- let futureEvent = this._eventQueue.shift();
89
- // `eventToAddToBatch` is used to keep track of an event that has been removed
90
- // from the queue, but has not yet been added to a batch.
91
- // This prevents losing an event if a `sendBatch` or `createBatch` call fails
92
- // before the event is added to a batch.
93
- let eventToAddToBatch;
94
- while (!this._loopAbortSignal.aborted) {
95
- try {
96
- if (!isDefined(batch)) {
97
- batch = await this._createBatch();
98
- }
99
- const timeSinceLastBatchCreation = Date.now() - this._lastBatchCreationTime;
100
- const maximumTimeToWaitForEvent = batch.count
101
- ? Math.max(this._maxWaitTimeInMs - timeSinceLastBatchCreation, 0)
102
- : this._maxWaitTimeInMs;
103
- const event = eventToAddToBatch !== null && eventToAddToBatch !== void 0 ? eventToAddToBatch : (await Promise.race([futureEvent, delay(maximumTimeToWaitForEvent)]));
104
- if (!event) {
105
- // We didn't receive an event within the allotted time.
106
- // Send the existing batch if it has events in it.
107
- if (batch.count) {
108
- await this._producer.sendBatch(batch);
109
- this._reportSuccess();
110
- batch = await this._createBatch();
111
- }
112
- continue;
113
- }
114
- else if (!eventToAddToBatch) {
115
- eventToAddToBatch = event;
116
- // We received an event, so get a promise for the next one.
117
- futureEvent = this._eventQueue.shift();
118
- }
119
- const didAdd = batch.tryAdd(event);
120
- if (didAdd) {
121
- // This event will definitely make it to one of the user-provided handlers
122
- // since it was added to a batch.
123
- // Store it so we can return it in a handler later.
124
- this._batchedEvents.push(event);
125
- // Clear reference to existing event since it has been added to the batch.
126
- eventToAddToBatch = undefined;
127
- }
128
- if (didAdd && batch.count >= this._maxBufferSize) {
129
- // Whenever batch.count exceeds the max count of buffered events, send the batch.
130
- await this._producer.sendBatch(batch);
131
- this._reportSuccess();
132
- batch = await this._createBatch();
133
- }
134
- else if (!didAdd && batch.count) {
135
- // If the event wasn't able to be added and the current batch isn't empty,
136
- // attempt to send the current batch and add the event to a new batch.
137
- await this._producer.sendBatch(batch);
138
- this._reportSuccess();
139
- batch = await this._createBatch();
140
- }
141
- if (!didAdd && !batch.tryAdd(event)) {
142
- // TODO: Report MaxMesageSizeExceeded error. Mimic service's error.
143
- this._reportFailure(new Error("Placeholder for max message size exceeded"), event);
144
- }
145
- else if (!didAdd) {
146
- // Handles the case where the event _was_ successfull added to the new batch.
147
- this._batchedEvents.push(event);
148
- }
149
- // Clear reference to existing event since it has been added to the batch.
150
- eventToAddToBatch = undefined;
151
- }
152
- catch (err) {
153
- if (!isObjectWithProperties(err, ["name"]) || err.name !== "AbortError") {
154
- this._reportFailure(err);
155
- batch = undefined;
156
- this._batchedEvents = [];
157
- }
158
- }
159
- }
160
- }
161
- /**
162
- * Helper method that returns an `EventDataBatch`.
163
- * This also has the side effects of
164
- * - keeping track of batch creation time: needed for maxWaitTime calculations.
165
- * - clearing reference to batched events.
166
- * - incrementing the readiness: creating a new batch indicates the buffer
167
- * should have room, so we can resolve some pending `ready()` calls.
168
- */
169
- async _createBatch() {
170
- this._lastBatchCreationTime = Date.now();
171
- this._batchedEvents = [];
172
- const batch = await this._producer.createBatch({
173
- partitionId: this._partitionId
174
- });
175
- this._incrementReadiness();
176
- return batch;
177
- }
178
- /**
179
- * This method will resolve as many pending `ready()` calls as it can
180
- * based on how much space remains in the buffer.
181
- *
182
- * If the channel is currently flushing, this is a no-op. This prevents
183
- * `enqueueEvent` calls from adding the event to the buffer until flushing
184
- * completes.
185
- */
186
- _incrementReadiness() {
187
- var _a;
188
- if (this._flushState.isFlushing) {
189
- return;
190
- }
191
- const currentBufferedCount = this.getCurrentBufferedCount();
192
- const num = Math.min(this._maxBufferSize - currentBufferedCount, this._readyQueue.length);
193
- for (let i = 0; i < num; i++) {
194
- (_a = this._readyQueue.shift()) === null || _a === void 0 ? void 0 : _a.resolve();
195
- }
196
- }
197
- /**
198
- * Calls the user-provided `onSendEventsSuccessHandler` with the events
199
- * that were successfully sent.
200
- */
201
- _reportSuccess() {
202
- var _a;
203
- this._bufferCount = this._bufferCount - this._batchedEvents.length;
204
- this._updateFlushState();
205
- (_a = this._onSendEventsSuccessHandler) === null || _a === void 0 ? void 0 : _a.call(this, {
206
- events: this._batchedEvents,
207
- partitionId: this._partitionId
208
- }).catch((e) => {
209
- logger.error(`The following error occured in the onSendEventsSuccessHandler: ${JSON.stringify(e, undefined, " ")}`);
210
- });
211
- }
212
- /**
213
- * Calls the user-provided `onSendEventsErrorHandler` with an error and the events
214
- * that were not successfully sent.
215
- */
216
- _reportFailure(err, event) {
217
- this._bufferCount = this._bufferCount - (event ? 1 : this._batchedEvents.length);
218
- this._updateFlushState();
219
- this._onSendEventsErrorHandler({
220
- error: err,
221
- events: event ? [event] : this._batchedEvents,
222
- partitionId: this._partitionId
223
- }).catch((e) => {
224
- logger.error(`The following error occured in the onSendEventsErrorHandler: ${JSON.stringify(e, undefined, " ")}`);
225
- });
226
- }
227
- /**
228
- * Updates the channel's flush state once the size of the
229
- * event buffer has decreased to 0.
230
- */
231
- _updateFlushState() {
232
- const state = this._flushState;
233
- if (!state.isFlushing || this.getCurrentBufferedCount() !== 0) {
234
- return;
235
- }
236
- state.resolve();
237
- this._flushState = { isFlushing: false };
238
- this._incrementReadiness();
239
- }
240
- }
241
- //# sourceMappingURL=batchingPartitionChannel.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"batchingPartitionChannel.js","sourceRoot":"","sources":["../../src/batchingPartitionChannel.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { AmqpAnnotatedMessage, delay } from \"@azure/core-amqp\";\nimport {\n EventData,\n EventDataBatch,\n EventHubBufferedProducerClientOptions,\n EventHubProducerClient,\n OperationOptions\n} from \"./index\";\nimport { AwaitableQueue } from \"./impl/awaitableQueue\";\nimport { isDefined, isObjectWithProperties } from \"./util/typeGuards\";\nimport { AbortSignalLike } from \"@azure/abort-controller\";\nimport { getPromiseParts } from \"./util/getPromiseParts\";\nimport { logger } from \"./log\";\n\nexport interface BatchingPartitionChannelProps {\n loopAbortSignal: AbortSignalLike;\n maxBufferSize: number;\n maxWaitTimeInMs: number;\n partitionId: string;\n producer: EventHubProducerClient;\n /**\n * The handler to call once a batch has successfully published.\n */\n onSendEventsSuccessHandler?: EventHubBufferedProducerClientOptions[\"onSendEventsSuccessHandler\"];\n /**\n * The handler to call when a batch fails to publish.\n */\n onSendEventsErrorHandler: EventHubBufferedProducerClientOptions[\"onSendEventsErrorHandler\"];\n}\n\n/**\n * The `BatchingPartitionChannel` is responsible for accepting enqueued events\n * and optimally batching and sending them to an Event Hub.\n * @internal\n */\nexport class BatchingPartitionChannel {\n private _eventQueue = new AwaitableQueue<EventData | AmqpAnnotatedMessage>();\n private _batchedEvents: Array<EventData | AmqpAnnotatedMessage> = [];\n private _bufferCount: number = 0;\n private _readyQueue: Array<{\n resolve: (value: void) => void;\n reject: (reason?: any) => void;\n }> = [];\n private _flushState:\n | { isFlushing: false }\n | { isFlushing: true; currentPromise: Promise<void>; resolve: () => void } = {\n isFlushing: false\n };\n private _isRunning: boolean = false;\n private _lastBatchCreationTime: number = 0;\n private _loopAbortSignal: AbortSignalLike;\n private _maxBufferSize: number;\n private _maxWaitTimeInMs: number;\n private _onSendEventsErrorHandler: EventHubBufferedProducerClientOptions[\"onSendEventsErrorHandler\"];\n private _onSendEventsSuccessHandler?: EventHubBufferedProducerClientOptions[\"onSendEventsSuccessHandler\"];\n\n private _partitionId: string;\n private _producer: EventHubProducerClient;\n\n constructor({\n loopAbortSignal,\n maxBufferSize,\n maxWaitTimeInMs,\n onSendEventsErrorHandler,\n onSendEventsSuccessHandler,\n partitionId,\n producer\n }: BatchingPartitionChannelProps) {\n this._loopAbortSignal = loopAbortSignal;\n this._maxBufferSize = maxBufferSize;\n this._maxWaitTimeInMs = maxWaitTimeInMs;\n this._onSendEventsErrorHandler = onSendEventsErrorHandler;\n this._onSendEventsSuccessHandler = onSendEventsSuccessHandler;\n this._partitionId = partitionId;\n this._producer = producer;\n }\n\n getCurrentBufferedCount(): number {\n return this._bufferCount;\n }\n\n async enqueueEvent(event: EventData | AmqpAnnotatedMessage): Promise<void> {\n await this._ready();\n this._eventQueue.push(event);\n this._bufferCount++;\n\n if (!this._isRunning) {\n this._isRunning = true;\n this._startPublishLoop().catch((e) => {\n logger.error(\n `The following error occured during batch creation or sending: ${JSON.stringify(\n e,\n undefined,\n \" \"\n )}`\n );\n });\n }\n }\n\n /**\n * Sets the flush state so that no new events can be enqueued until\n * all the currently buffered events are sent to the Event Hub.\n *\n * Returns a promise that resolves once flushing is complete.\n */\n async flush(_options: OperationOptions = {}): Promise<void> {\n const state = this._flushState;\n if (state.isFlushing) {\n return state.currentPromise;\n }\n\n if (this.getCurrentBufferedCount() === 0) {\n return Promise.resolve();\n }\n\n const { promise, resolve } = getPromiseParts<void>();\n this._flushState = { isFlushing: true, currentPromise: promise, resolve };\n\n return promise;\n }\n\n /**\n * Returns a promise that resolves once there is room for events to be added\n * to the buffer.\n */\n private _ready(): Promise<void> {\n const currentBufferedCount = this.getCurrentBufferedCount();\n\n // If the buffer isn't full and we don't have any pending `ready()` calls,\n // then it's safe to return right away.\n if (\n currentBufferedCount < this._maxBufferSize &&\n !this._readyQueue.length &&\n !this._flushState.isFlushing\n ) {\n return Promise.resolve();\n }\n\n const { promise: readyPromise, reject, resolve } = getPromiseParts<void>();\n this._readyQueue.push({ resolve, reject });\n\n return readyPromise;\n }\n\n /**\n * Starts the loop that creates batches and sends them to the Event Hub.\n *\n * The loop will run until the `_loopAbortSignal` is aborted.\n */\n private async _startPublishLoop() {\n let batch: EventDataBatch | undefined;\n let futureEvent = this._eventQueue.shift();\n // `eventToAddToBatch` is used to keep track of an event that has been removed\n // from the queue, but has not yet been added to a batch.\n // This prevents losing an event if a `sendBatch` or `createBatch` call fails\n // before the event is added to a batch.\n let eventToAddToBatch: EventData | AmqpAnnotatedMessage | undefined;\n while (!this._loopAbortSignal.aborted) {\n try {\n if (!isDefined(batch)) {\n batch = await this._createBatch();\n }\n const timeSinceLastBatchCreation = Date.now() - this._lastBatchCreationTime;\n const maximumTimeToWaitForEvent = batch.count\n ? Math.max(this._maxWaitTimeInMs - timeSinceLastBatchCreation, 0)\n : this._maxWaitTimeInMs;\n\n const event =\n eventToAddToBatch ??\n (await Promise.race([futureEvent, delay<void>(maximumTimeToWaitForEvent)]));\n\n if (!event) {\n // We didn't receive an event within the allotted time.\n // Send the existing batch if it has events in it.\n if (batch.count) {\n await this._producer.sendBatch(batch);\n this._reportSuccess();\n batch = await this._createBatch();\n }\n continue;\n } else if (!eventToAddToBatch) {\n eventToAddToBatch = event;\n // We received an event, so get a promise for the next one.\n futureEvent = this._eventQueue.shift();\n }\n\n const didAdd = batch.tryAdd(event);\n if (didAdd) {\n // This event will definitely make it to one of the user-provided handlers\n // since it was added to a batch.\n // Store it so we can return it in a handler later.\n this._batchedEvents.push(event);\n // Clear reference to existing event since it has been added to the batch.\n eventToAddToBatch = undefined;\n }\n\n if (didAdd && batch.count >= this._maxBufferSize) {\n // Whenever batch.count exceeds the max count of buffered events, send the batch.\n await this._producer.sendBatch(batch);\n this._reportSuccess();\n batch = await this._createBatch();\n } else if (!didAdd && batch.count) {\n // If the event wasn't able to be added and the current batch isn't empty,\n // attempt to send the current batch and add the event to a new batch.\n await this._producer.sendBatch(batch);\n this._reportSuccess();\n batch = await this._createBatch();\n }\n\n if (!didAdd && !batch.tryAdd(event)) {\n // TODO: Report MaxMesageSizeExceeded error. Mimic service's error.\n this._reportFailure(new Error(\"Placeholder for max message size exceeded\"), event);\n } else if (!didAdd) {\n // Handles the case where the event _was_ successfull added to the new batch.\n this._batchedEvents.push(event);\n }\n // Clear reference to existing event since it has been added to the batch.\n eventToAddToBatch = undefined;\n } catch (err) {\n if (!isObjectWithProperties(err, [\"name\"]) || err.name !== \"AbortError\") {\n this._reportFailure(err);\n batch = undefined;\n this._batchedEvents = [];\n }\n }\n }\n }\n\n /**\n * Helper method that returns an `EventDataBatch`.\n * This also has the side effects of\n * - keeping track of batch creation time: needed for maxWaitTime calculations.\n * - clearing reference to batched events.\n * - incrementing the readiness: creating a new batch indicates the buffer\n * should have room, so we can resolve some pending `ready()` calls.\n */\n private async _createBatch(): Promise<EventDataBatch> {\n this._lastBatchCreationTime = Date.now();\n this._batchedEvents = [];\n const batch = await this._producer.createBatch({\n partitionId: this._partitionId\n });\n this._incrementReadiness();\n return batch;\n }\n\n /**\n * This method will resolve as many pending `ready()` calls as it can\n * based on how much space remains in the buffer.\n *\n * If the channel is currently flushing, this is a no-op. This prevents\n * `enqueueEvent` calls from adding the event to the buffer until flushing\n * completes.\n */\n private _incrementReadiness() {\n if (this._flushState.isFlushing) {\n return;\n }\n const currentBufferedCount = this.getCurrentBufferedCount();\n const num = Math.min(this._maxBufferSize - currentBufferedCount, this._readyQueue.length);\n for (let i = 0; i < num; i++) {\n this._readyQueue.shift()?.resolve();\n }\n }\n\n /**\n * Calls the user-provided `onSendEventsSuccessHandler` with the events\n * that were successfully sent.\n */\n private _reportSuccess() {\n this._bufferCount = this._bufferCount - this._batchedEvents.length;\n this._updateFlushState();\n this._onSendEventsSuccessHandler?.({\n events: this._batchedEvents,\n partitionId: this._partitionId\n }).catch((e) => {\n logger.error(\n `The following error occured in the onSendEventsSuccessHandler: ${JSON.stringify(\n e,\n undefined,\n \" \"\n )}`\n );\n });\n }\n\n /**\n * Calls the user-provided `onSendEventsErrorHandler` with an error and the events\n * that were not successfully sent.\n */\n private _reportFailure(err: any, event?: EventData | AmqpAnnotatedMessage) {\n this._bufferCount = this._bufferCount - (event ? 1 : this._batchedEvents.length);\n this._updateFlushState();\n this._onSendEventsErrorHandler({\n error: err,\n events: event ? [event] : this._batchedEvents,\n partitionId: this._partitionId\n }).catch((e) => {\n logger.error(\n `The following error occured in the onSendEventsErrorHandler: ${JSON.stringify(\n e,\n undefined,\n \" \"\n )}`\n );\n });\n }\n\n /**\n * Updates the channel's flush state once the size of the\n * event buffer has decreased to 0.\n */\n private _updateFlushState() {\n const state = this._flushState;\n if (!state.isFlushing || this.getCurrentBufferedCount() !== 0) {\n return;\n }\n\n state.resolve();\n\n this._flushState = { isFlushing: false };\n this._incrementReadiness();\n }\n}\n"]}