@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
package/dist/index.js CHANGED
@@ -7,7 +7,6 @@ function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'defau
7
7
  var logger$1 = require('@azure/logger');
8
8
  var coreAuth = require('@azure/core-auth');
9
9
  var os = require('os');
10
- var os__default = _interopDefault(os);
11
10
  var coreAmqp = require('@azure/core-amqp');
12
11
  var uuid = require('uuid');
13
12
  var rheaPromise = require('rhea-promise');
@@ -93,7 +92,7 @@ function getRuntimeInfo() {
93
92
  */
94
93
  const packageJsonInfo = {
95
94
  name: "@azure/event-hubs",
96
- version: "5.7.0-beta.1"
95
+ version: "5.7.0"
97
96
  };
98
97
 
99
98
  // Copyright (c) Microsoft Corporation.
@@ -2186,43 +2185,26 @@ const TRACEPARENT_PROPERTY = "Diagnostic-Id";
2186
2185
  * @param eventData - The `EventData` or `AmqpAnnotatedMessage` to instrument.
2187
2186
  * @param span - The `Span` containing the context to propagate tracing information.
2188
2187
  */
2189
- function instrumentEventData(eventData, options, entityPath, host) {
2188
+ function instrumentEventData(eventData, span) {
2190
2189
  const props = isAmqpAnnotatedMessage(eventData)
2191
2190
  ? eventData.applicationProperties
2192
2191
  : eventData.properties;
2193
- // check if the event has already been instrumented
2194
- const previouslyInstrumented = Boolean(props === null || props === void 0 ? void 0 : props[TRACEPARENT_PROPERTY]);
2195
- if (previouslyInstrumented) {
2196
- return { event: eventData, spanContext: undefined };
2192
+ if (props && props[TRACEPARENT_PROPERTY]) {
2193
+ return eventData;
2197
2194
  }
2198
- const { span: messageSpan } = createMessageSpan(options, { entityPath, host });
2199
- try {
2200
- if (!messageSpan.isRecording()) {
2201
- return {
2202
- event: eventData,
2203
- spanContext: undefined
2204
- };
2205
- }
2206
- const traceParent = coreTracing.getTraceParentHeader(messageSpan.spanContext());
2207
- if (traceParent && coreTracing.isSpanContextValid(messageSpan.spanContext())) {
2208
- const copiedProps = Object.assign({}, props);
2209
- // create a copy so the original isn't modified
2210
- if (isAmqpAnnotatedMessage(eventData)) {
2211
- eventData = Object.assign(Object.assign({}, eventData), { applicationProperties: copiedProps });
2212
- }
2213
- else {
2214
- eventData = Object.assign(Object.assign({}, eventData), { properties: copiedProps });
2215
- }
2216
- copiedProps[TRACEPARENT_PROPERTY] = traceParent;
2217
- }
2218
- return {
2219
- event: eventData,
2220
- spanContext: messageSpan.spanContext()
2221
- };
2195
+ const copiedProps = Object.assign({}, props);
2196
+ // create a copy so the original isn't modified
2197
+ if (isAmqpAnnotatedMessage(eventData)) {
2198
+ eventData = Object.assign(Object.assign({}, eventData), { applicationProperties: copiedProps });
2222
2199
  }
2223
- finally {
2224
- messageSpan.end();
2200
+ else {
2201
+ eventData = Object.assign(Object.assign({}, eventData), { properties: copiedProps });
2202
+ }
2203
+ const traceParent = coreTracing.getTraceParentHeader(span.spanContext());
2204
+ if (traceParent) {
2205
+ copiedProps[TRACEPARENT_PROPERTY] = traceParent;
2225
2206
  }
2207
+ return eventData;
2226
2208
  }
2227
2209
  /**
2228
2210
  * Extracts the `SpanContext` from an `EventData` if the context exists.
@@ -3839,12 +3821,23 @@ class EventDataBatchImpl {
3839
3821
  * @returns A boolean value indicating if the event data has been added to the batch or not.
3840
3822
  */
3841
3823
  tryAdd(eventData, options = {}) {
3824
+ var _a;
3842
3825
  throwTypeErrorIfParameterMissing(this._context.connectionId, "tryAdd", "eventData", eventData);
3843
3826
  options = convertTryAddOptionsForCompatibility(options);
3844
- const { entityPath, host } = this._context.config;
3845
- const { event: instrumentedEvent, spanContext } = instrumentEventData(eventData, options, entityPath, host);
3827
+ // check if the event has already been instrumented
3828
+ const previouslyInstrumented = Boolean((_a = (isAmqpAnnotatedMessage(eventData)
3829
+ ? eventData.applicationProperties
3830
+ : eventData.properties)) === null || _a === void 0 ? void 0 : _a[TRACEPARENT_PROPERTY] // Event Data maps properties to applicationProperties.
3831
+ );
3832
+ let spanContext;
3833
+ if (!previouslyInstrumented) {
3834
+ const { span: messageSpan } = createMessageSpan(options, this._context.config);
3835
+ eventData = instrumentEventData(eventData, messageSpan);
3836
+ spanContext = messageSpan.spanContext();
3837
+ messageSpan.end();
3838
+ }
3846
3839
  // Convert EventData to RheaMessage.
3847
- const amqpMessage = toRheaMessage(instrumentedEvent, this._partitionKey);
3840
+ const amqpMessage = toRheaMessage(eventData, this._partitionKey);
3848
3841
  const encodedMessage = rheaPromise.message.encode(amqpMessage);
3849
3842
  let currentSize = this._sizeInBytes;
3850
3843
  // The first time an event is added, we need to calculate
@@ -4354,7 +4347,15 @@ class EventHubProducerClient {
4354
4347
  partitionId = expectedOptions.partitionId;
4355
4348
  partitionKey = expectedOptions.partitionKey;
4356
4349
  for (let i = 0; i < batch.length; i++) {
4357
- batch[i] = instrumentEventData(batch[i], options, this._context.config.entityPath, this._context.config.host).event;
4350
+ const event = batch[i];
4351
+ if (!event.properties || !event.properties[TRACEPARENT_PROPERTY]) {
4352
+ const { span: messageSpan } = createMessageSpan(options, this._context.config);
4353
+ // since these message spans are created from same context as the send span,
4354
+ // these message spans don't need to be linked.
4355
+ // replace the original event with the instrumented one
4356
+ batch[i] = instrumentEventData(batch[i], messageSpan);
4357
+ messageSpan.end();
4358
+ }
4358
4359
  }
4359
4360
  }
4360
4361
  if (isDefined(partitionId) && isDefined(partitionKey)) {
@@ -4452,697 +4453,6 @@ class EventHubProducerClient {
4452
4453
  }
4453
4454
  }
4454
4455
 
4455
- // Copyright (c) Microsoft Corporation.
4456
- // Licensed under the MIT license.
4457
- /**
4458
- * `AwaitableQueue` stores items in the order that they are received.
4459
- *
4460
- * This differs from ordinary Queues in that `shift` returns a Promise for a value.
4461
- * This allows a consumer of the queue to request an item that the queue does not yet have.
4462
- *
4463
- * @hidden
4464
- */
4465
- class AwaitableQueue {
4466
- constructor() {
4467
- this._resolvers = [];
4468
- this._items = [];
4469
- }
4470
- size() {
4471
- return this._items.length;
4472
- }
4473
- /**
4474
- * Returns a Promise that will resolve with the next item in the queue.
4475
- */
4476
- shift() {
4477
- const item = this._items.shift();
4478
- if (typeof item !== "undefined") {
4479
- return Promise.resolve(item);
4480
- }
4481
- return new Promise((resolve) => this._resolvers.push(resolve));
4482
- }
4483
- /**
4484
- * Appends new item to the queue.
4485
- */
4486
- push(item) {
4487
- if (!this._resolveNextItem(item)) {
4488
- this._items.push(item);
4489
- }
4490
- }
4491
- _resolveNextItem(item) {
4492
- const resolver = this._resolvers.shift();
4493
- if (!resolver) {
4494
- return false;
4495
- }
4496
- resolver(item);
4497
- return true;
4498
- }
4499
- }
4500
-
4501
- // Copyright (c) Microsoft Corporation.
4502
- // Licensed under the MIT license.
4503
- /**
4504
- * @internal
4505
- * Returns a promise and the promise's resolve and reject methods.
4506
- */
4507
- function getPromiseParts() {
4508
- let resolver;
4509
- let rejector;
4510
- const promise = new Promise((resolve, reject) => {
4511
- resolver = resolve;
4512
- rejector = reject;
4513
- });
4514
- return {
4515
- promise,
4516
- resolve: resolver,
4517
- reject: rejector
4518
- };
4519
- }
4520
-
4521
- // Copyright (c) Microsoft Corporation.
4522
- /**
4523
- * The `BatchingPartitionChannel` is responsible for accepting enqueued events
4524
- * and optimally batching and sending them to an Event Hub.
4525
- * @internal
4526
- */
4527
- class BatchingPartitionChannel {
4528
- constructor({ loopAbortSignal, maxBufferSize, maxWaitTimeInMs, onSendEventsErrorHandler, onSendEventsSuccessHandler, partitionId, producer }) {
4529
- this._eventQueue = new AwaitableQueue();
4530
- this._batchedEvents = [];
4531
- this._bufferCount = 0;
4532
- this._readyQueue = [];
4533
- this._flushState = {
4534
- isFlushing: false
4535
- };
4536
- this._isRunning = false;
4537
- this._lastBatchCreationTime = 0;
4538
- this._loopAbortSignal = loopAbortSignal;
4539
- this._maxBufferSize = maxBufferSize;
4540
- this._maxWaitTimeInMs = maxWaitTimeInMs;
4541
- this._onSendEventsErrorHandler = onSendEventsErrorHandler;
4542
- this._onSendEventsSuccessHandler = onSendEventsSuccessHandler;
4543
- this._partitionId = partitionId;
4544
- this._producer = producer;
4545
- }
4546
- getCurrentBufferedCount() {
4547
- return this._bufferCount;
4548
- }
4549
- async enqueueEvent(event) {
4550
- await this._ready();
4551
- this._eventQueue.push(event);
4552
- this._bufferCount++;
4553
- if (!this._isRunning) {
4554
- this._isRunning = true;
4555
- this._startPublishLoop().catch((e) => {
4556
- logger.error(`The following error occured during batch creation or sending: ${JSON.stringify(e, undefined, " ")}`);
4557
- });
4558
- }
4559
- }
4560
- /**
4561
- * Sets the flush state so that no new events can be enqueued until
4562
- * all the currently buffered events are sent to the Event Hub.
4563
- *
4564
- * Returns a promise that resolves once flushing is complete.
4565
- */
4566
- async flush(_options = {}) {
4567
- const state = this._flushState;
4568
- if (state.isFlushing) {
4569
- return state.currentPromise;
4570
- }
4571
- if (this.getCurrentBufferedCount() === 0) {
4572
- return Promise.resolve();
4573
- }
4574
- const { promise, resolve } = getPromiseParts();
4575
- this._flushState = { isFlushing: true, currentPromise: promise, resolve };
4576
- return promise;
4577
- }
4578
- /**
4579
- * Returns a promise that resolves once there is room for events to be added
4580
- * to the buffer.
4581
- */
4582
- _ready() {
4583
- const currentBufferedCount = this.getCurrentBufferedCount();
4584
- // If the buffer isn't full and we don't have any pending `ready()` calls,
4585
- // then it's safe to return right away.
4586
- if (currentBufferedCount < this._maxBufferSize &&
4587
- !this._readyQueue.length &&
4588
- !this._flushState.isFlushing) {
4589
- return Promise.resolve();
4590
- }
4591
- const { promise: readyPromise, reject, resolve } = getPromiseParts();
4592
- this._readyQueue.push({ resolve, reject });
4593
- return readyPromise;
4594
- }
4595
- /**
4596
- * Starts the loop that creates batches and sends them to the Event Hub.
4597
- *
4598
- * The loop will run until the `_loopAbortSignal` is aborted.
4599
- */
4600
- async _startPublishLoop() {
4601
- let batch;
4602
- let futureEvent = this._eventQueue.shift();
4603
- // `eventToAddToBatch` is used to keep track of an event that has been removed
4604
- // from the queue, but has not yet been added to a batch.
4605
- // This prevents losing an event if a `sendBatch` or `createBatch` call fails
4606
- // before the event is added to a batch.
4607
- let eventToAddToBatch;
4608
- while (!this._loopAbortSignal.aborted) {
4609
- try {
4610
- if (!isDefined(batch)) {
4611
- batch = await this._createBatch();
4612
- }
4613
- const timeSinceLastBatchCreation = Date.now() - this._lastBatchCreationTime;
4614
- const maximumTimeToWaitForEvent = batch.count
4615
- ? Math.max(this._maxWaitTimeInMs - timeSinceLastBatchCreation, 0)
4616
- : this._maxWaitTimeInMs;
4617
- const event = eventToAddToBatch !== null && eventToAddToBatch !== void 0 ? eventToAddToBatch : (await Promise.race([futureEvent, coreAmqp.delay(maximumTimeToWaitForEvent)]));
4618
- if (!event) {
4619
- // We didn't receive an event within the allotted time.
4620
- // Send the existing batch if it has events in it.
4621
- if (batch.count) {
4622
- await this._producer.sendBatch(batch);
4623
- this._reportSuccess();
4624
- batch = await this._createBatch();
4625
- }
4626
- continue;
4627
- }
4628
- else if (!eventToAddToBatch) {
4629
- eventToAddToBatch = event;
4630
- // We received an event, so get a promise for the next one.
4631
- futureEvent = this._eventQueue.shift();
4632
- }
4633
- const didAdd = batch.tryAdd(event);
4634
- if (didAdd) {
4635
- // This event will definitely make it to one of the user-provided handlers
4636
- // since it was added to a batch.
4637
- // Store it so we can return it in a handler later.
4638
- this._batchedEvents.push(event);
4639
- // Clear reference to existing event since it has been added to the batch.
4640
- eventToAddToBatch = undefined;
4641
- }
4642
- if (didAdd && batch.count >= this._maxBufferSize) {
4643
- // Whenever batch.count exceeds the max count of buffered events, send the batch.
4644
- await this._producer.sendBatch(batch);
4645
- this._reportSuccess();
4646
- batch = await this._createBatch();
4647
- }
4648
- else if (!didAdd && batch.count) {
4649
- // If the event wasn't able to be added and the current batch isn't empty,
4650
- // attempt to send the current batch and add the event to a new batch.
4651
- await this._producer.sendBatch(batch);
4652
- this._reportSuccess();
4653
- batch = await this._createBatch();
4654
- }
4655
- if (!didAdd && !batch.tryAdd(event)) {
4656
- // TODO: Report MaxMesageSizeExceeded error. Mimic service's error.
4657
- this._reportFailure(new Error("Placeholder for max message size exceeded"), event);
4658
- }
4659
- else if (!didAdd) {
4660
- // Handles the case where the event _was_ successfull added to the new batch.
4661
- this._batchedEvents.push(event);
4662
- }
4663
- // Clear reference to existing event since it has been added to the batch.
4664
- eventToAddToBatch = undefined;
4665
- }
4666
- catch (err) {
4667
- if (!isObjectWithProperties(err, ["name"]) || err.name !== "AbortError") {
4668
- this._reportFailure(err);
4669
- batch = undefined;
4670
- this._batchedEvents = [];
4671
- }
4672
- }
4673
- }
4674
- }
4675
- /**
4676
- * Helper method that returns an `EventDataBatch`.
4677
- * This also has the side effects of
4678
- * - keeping track of batch creation time: needed for maxWaitTime calculations.
4679
- * - clearing reference to batched events.
4680
- * - incrementing the readiness: creating a new batch indicates the buffer
4681
- * should have room, so we can resolve some pending `ready()` calls.
4682
- */
4683
- async _createBatch() {
4684
- this._lastBatchCreationTime = Date.now();
4685
- this._batchedEvents = [];
4686
- const batch = await this._producer.createBatch({
4687
- partitionId: this._partitionId
4688
- });
4689
- this._incrementReadiness();
4690
- return batch;
4691
- }
4692
- /**
4693
- * This method will resolve as many pending `ready()` calls as it can
4694
- * based on how much space remains in the buffer.
4695
- *
4696
- * If the channel is currently flushing, this is a no-op. This prevents
4697
- * `enqueueEvent` calls from adding the event to the buffer until flushing
4698
- * completes.
4699
- */
4700
- _incrementReadiness() {
4701
- var _a;
4702
- if (this._flushState.isFlushing) {
4703
- return;
4704
- }
4705
- const currentBufferedCount = this.getCurrentBufferedCount();
4706
- const num = Math.min(this._maxBufferSize - currentBufferedCount, this._readyQueue.length);
4707
- for (let i = 0; i < num; i++) {
4708
- (_a = this._readyQueue.shift()) === null || _a === void 0 ? void 0 : _a.resolve();
4709
- }
4710
- }
4711
- /**
4712
- * Calls the user-provided `onSendEventsSuccessHandler` with the events
4713
- * that were successfully sent.
4714
- */
4715
- _reportSuccess() {
4716
- var _a;
4717
- this._bufferCount = this._bufferCount - this._batchedEvents.length;
4718
- this._updateFlushState();
4719
- (_a = this._onSendEventsSuccessHandler) === null || _a === void 0 ? void 0 : _a.call(this, {
4720
- events: this._batchedEvents,
4721
- partitionId: this._partitionId
4722
- }).catch((e) => {
4723
- logger.error(`The following error occured in the onSendEventsSuccessHandler: ${JSON.stringify(e, undefined, " ")}`);
4724
- });
4725
- }
4726
- /**
4727
- * Calls the user-provided `onSendEventsErrorHandler` with an error and the events
4728
- * that were not successfully sent.
4729
- */
4730
- _reportFailure(err, event) {
4731
- this._bufferCount = this._bufferCount - (event ? 1 : this._batchedEvents.length);
4732
- this._updateFlushState();
4733
- this._onSendEventsErrorHandler({
4734
- error: err,
4735
- events: event ? [event] : this._batchedEvents,
4736
- partitionId: this._partitionId
4737
- }).catch((e) => {
4738
- logger.error(`The following error occured in the onSendEventsErrorHandler: ${JSON.stringify(e, undefined, " ")}`);
4739
- });
4740
- }
4741
- /**
4742
- * Updates the channel's flush state once the size of the
4743
- * event buffer has decreased to 0.
4744
- */
4745
- _updateFlushState() {
4746
- const state = this._flushState;
4747
- if (!state.isFlushing || this.getCurrentBufferedCount() !== 0) {
4748
- return;
4749
- }
4750
- state.resolve();
4751
- this._flushState = { isFlushing: false };
4752
- this._incrementReadiness();
4753
- }
4754
- }
4755
-
4756
- // Copyright (c) Microsoft Corporation.
4757
- function mapPartitionKeyToId(partitionKey, partitionCount) {
4758
- const hash = computeHash(Buffer.from(partitionKey, "utf8"));
4759
- const hashedParitionKey = castToInt16(hash.c ^ hash.b);
4760
- return Math.abs(hashedParitionKey % partitionCount);
4761
- }
4762
- function readUInt32(data, offset) {
4763
- return os__default.endianness() === "BE" ? data.readUInt32BE(offset) : data.readUInt32LE(offset);
4764
- }
4765
- function castToInt16(n) {
4766
- return new Int16Array([n])[0];
4767
- }
4768
- function computeHash(data, seed1 = 0, seed2 = 0) {
4769
- let a, b, c;
4770
- a = b = c = 0xdeadbeef + data.length + seed1;
4771
- c += seed2;
4772
- let index = 0, size = data.length;
4773
- while (size > 12) {
4774
- a += readUInt32(data, index);
4775
- b += readUInt32(data, index + 4);
4776
- c += readUInt32(data, index + 8);
4777
- a -= c;
4778
- a ^= (c << 4) | (c >>> 28);
4779
- c += b;
4780
- b -= a;
4781
- b ^= (a << 6) | (a >>> 26);
4782
- a += c;
4783
- c -= b;
4784
- c ^= (b << 8) | (b >>> 24);
4785
- b += a;
4786
- a -= c;
4787
- a ^= (c << 16) | (c >>> 16);
4788
- c += b;
4789
- b -= a;
4790
- b ^= (a << 19) | (a >>> 13);
4791
- a += c;
4792
- c -= b;
4793
- c ^= (b << 4) | (b >>> 28);
4794
- b += a;
4795
- index += 12;
4796
- size -= 12;
4797
- }
4798
- let curr = size;
4799
- switch (curr) {
4800
- case 12:
4801
- a += readUInt32(data, index);
4802
- b += readUInt32(data, index + 4);
4803
- c += readUInt32(data, index + 8);
4804
- break;
4805
- case 11:
4806
- c += data[index + 10] << 16;
4807
- curr = 10;
4808
- case 10:
4809
- c += data[index + 9] << 8;
4810
- curr = 9;
4811
- case 9:
4812
- c += data[index + 8];
4813
- curr = 8;
4814
- case 8:
4815
- b += readUInt32(data, index + 4);
4816
- a += readUInt32(data, index);
4817
- break;
4818
- case 7:
4819
- b += data[index + 6] << 16;
4820
- curr = 6;
4821
- case 6:
4822
- b += data[index + 5] << 8;
4823
- curr = 5;
4824
- case 5:
4825
- b += data[index + 4];
4826
- curr = 4;
4827
- case 4:
4828
- a += readUInt32(data, index);
4829
- break;
4830
- case 3:
4831
- a += data[index + 2] << 16;
4832
- curr = 2;
4833
- case 2:
4834
- a += data[index + 1] << 8;
4835
- curr = 1;
4836
- case 1:
4837
- a += data[index];
4838
- break;
4839
- case 0:
4840
- return { b: b >>> 0, c: c >>> 0 };
4841
- }
4842
- c ^= b;
4843
- c -= (b << 14) | (b >>> 18);
4844
- a ^= c;
4845
- a -= (c << 11) | (c >>> 21);
4846
- b ^= a;
4847
- b -= (a << 25) | (a >>> 7);
4848
- c ^= b;
4849
- c -= (b << 16) | (b >>> 16);
4850
- a ^= c;
4851
- a -= (c << 4) | (c >>> 28);
4852
- b ^= a;
4853
- b -= (a << 14) | (a >>> 18);
4854
- c ^= b;
4855
- c -= (b << 24) | (b >>> 8);
4856
- return { b: b >>> 0, c: c >>> 0 };
4857
- }
4858
-
4859
- // Copyright (c) Microsoft Corporation.
4860
- /**
4861
- * @internal
4862
- * Assigns a partition based on the partition ids it knows about and an optional partition id or partition key.
4863
- */
4864
- class PartitionAssigner {
4865
- constructor() {
4866
- this._partitions = [];
4867
- this._lastRoundRobinPartitionIndex = -1;
4868
- }
4869
- /**
4870
- * Set the partition ids that can be used when assigning a partition.
4871
- * @param partitionIds - All valid partition ids.
4872
- */
4873
- setPartitionIds(partitionIds) {
4874
- this._partitions = partitionIds;
4875
- }
4876
- /**
4877
- * Returns a partitionId from the list of partition ids set via `setPartitionIds`.
4878
- *
4879
- * If a partitionId is specified, then that will be returned directly.
4880
- * If a partitionKey is specified, then a partitionId will be calculated based on the partitionKey.
4881
- * Specifying both partitionId and partitionKey results in an error.
4882
- *
4883
- * If neither partitionId nor partitionKey are specified, then a partitionId will be selected
4884
- * based on a round-robin approach.
4885
- */
4886
- assignPartition({ partitionId, partitionKey }) {
4887
- if (isDefined(partitionId) && isDefined(partitionKey)) {
4888
- throw new Error(`The partitionId (${partitionId}) and partitionKey (${partitionKey}) cannot both be specified.`);
4889
- }
4890
- if (!this._partitions.length) {
4891
- throw new Error(`Unable to determine partitionIds, can't assign partitionId.`);
4892
- }
4893
- if (isDefined(partitionId) && this._partitions.includes(partitionId)) {
4894
- return partitionId;
4895
- }
4896
- if (isDefined(partitionKey)) {
4897
- return mapPartitionKeyToId(partitionKey, this._partitions.length).toString();
4898
- }
4899
- return this._assignRoundRobinPartition();
4900
- }
4901
- _assignRoundRobinPartition() {
4902
- const maxPartitionIndex = this._partitions.length - 1;
4903
- const proposedPartitionIndex = this._lastRoundRobinPartitionIndex + 1;
4904
- const nextPartitionIndex = proposedPartitionIndex > maxPartitionIndex ? 0 : proposedPartitionIndex;
4905
- this._lastRoundRobinPartitionIndex = nextPartitionIndex;
4906
- return this._partitions[nextPartitionIndex];
4907
- }
4908
- }
4909
-
4910
- // Copyright (c) Microsoft Corporation.
4911
- /**
4912
- * The `EventHubBufferedProducerClient`is used to publish events to a specific Event Hub.
4913
- *
4914
- * The `EventHubBufferedProducerClient` does not publish events immediately.
4915
- * Instead, events are buffered so they can be efficiently batched and published
4916
- * when the batch is full or the `maxWaitTimeInMs` has elapsed with no new events
4917
- * enqueued.
4918
- *
4919
- * Depending on the options specified when events are enqueued, they may be
4920
- * automatically assigned to a partition, grouped according to the specified partition key,
4921
- * or assigned a specifically requested partition.
4922
- *
4923
- * This model is intended to shift the burden of batch management from callers, at the cost of
4924
- * non-deterministic timing, for when events will be published. There are additional trade-offs
4925
- * to consider, as well:
4926
- * - If the application crashes, events in the buffer will not have been published. To prevent
4927
- * data loss, callers are encouraged to track publishing progress using the
4928
- * `onSendEventsSuccessHandler` and `onSendEventsErrorHandler` handlers.
4929
- * - Events specifying a partition key may be assigned a different partition than those using
4930
- * the same key with other producers.
4931
- * - In the unlikely event that a partition becomes temporarily unavailable, the
4932
- * `EventHubBufferedProducerClient` may take longer to recover than other producers.
4933
- *
4934
- * In scenarios where it is important to have events published immediately with a deterministic
4935
- * outcome, ensure that partition keys are assigned to a partition consistent with other
4936
- * publishers, or where maximizing availability is a requirement, using the
4937
- * `EventHubProducerClient` is recommended.
4938
- */
4939
- class EventHubBufferedProducerClient {
4940
- constructor(fullyQualifiedNamespaceOrConnectionString1, eventHubNameOrOptions2, credentialOrOptions3, options4) {
4941
- /**
4942
- * Controls the `abortSignal` passed to each `BatchingPartitionChannel`.
4943
- * Used to signal when a channel should stop waiting for events.
4944
- */
4945
- this._abortController = new abortController.AbortController();
4946
- /**
4947
- * Indicates whether the client has been explicitly closed.
4948
- */
4949
- this._isClosed = false;
4950
- /**
4951
- * Handles assigning partitions.
4952
- */
4953
- this._partitionAssigner = new PartitionAssigner();
4954
- /**
4955
- * The known partitionIds that will be used when assigning events to partitions.
4956
- */
4957
- this._partitionIds = [];
4958
- /**
4959
- * Mapping of partitionIds to `BatchingPartitionChannels`.
4960
- * Each `BatchingPartitionChannel` handles buffering events and backpressure independently.
4961
- */
4962
- this._partitionChannels = new Map();
4963
- if (typeof eventHubNameOrOptions2 !== "string") {
4964
- this._producer = new EventHubProducerClient(fullyQualifiedNamespaceOrConnectionString1, eventHubNameOrOptions2);
4965
- this._clientOptions = Object.assign({}, eventHubNameOrOptions2);
4966
- }
4967
- else if (!isCredential(credentialOrOptions3)) {
4968
- this._producer = new EventHubProducerClient(fullyQualifiedNamespaceOrConnectionString1, eventHubNameOrOptions2, credentialOrOptions3);
4969
- this._clientOptions = Object.assign({}, credentialOrOptions3);
4970
- }
4971
- else {
4972
- this._producer = new EventHubProducerClient(fullyQualifiedNamespaceOrConnectionString1, eventHubNameOrOptions2, credentialOrOptions3, options4);
4973
- this._clientOptions = Object.assign({}, options4);
4974
- }
4975
- }
4976
- /**
4977
- * @readonly
4978
- * The name of the Event Hub instance for which this client is created.
4979
- */
4980
- get eventHubName() {
4981
- return this._producer.eventHubName;
4982
- }
4983
- /**
4984
- * @readonly
4985
- * The fully qualified namespace of the Event Hub instance for which this client is created.
4986
- * This is likely to be similar to <yournamespace>.servicebus.windows.net.
4987
- */
4988
- get fullyQualifiedNamespace() {
4989
- return this._producer.fullyQualifiedNamespace;
4990
- }
4991
- /**
4992
- * Closes the AMQP connection to the Event Hub instance,
4993
- * returning a promise that will be resolved when disconnection is completed.
4994
- *
4995
- * This will wait for enqueued events to be flushed to the service before closing
4996
- * the connection.
4997
- * To close without flushing, set the `flush` option to `false`.
4998
- *
4999
- * @param options - The set of options to apply to the operation call.
5000
- * @returns Promise<void>
5001
- * @throws Error if the underlying connection encounters an error while closing.
5002
- */
5003
- async close(options = {}) {
5004
- if (!isDefined(options.flush) || options.flush === true) {
5005
- await this.flush(options);
5006
- }
5007
- // Calling abort signals to the BatchingPartitionChannels that they
5008
- // should stop reading/sending events.
5009
- this._abortController.abort();
5010
- return this._producer.close();
5011
- }
5012
- /**
5013
- * Enqueues an event into the buffer to be published to the Event Hub.
5014
- * If there is no capacity in the buffer when this method is invoked,
5015
- * it will wait for space to become available and ensure that the event
5016
- * has been enqueued.
5017
- *
5018
- * When this call returns, the event has been accepted into the buffer,
5019
- * but it may not have been published yet.
5020
- * Publishing will take place at a nondeterministic point in the future as the buffer is processed.
5021
- *
5022
- * @param events - An {@link EventData} or `AmqpAnnotatedMessage`.
5023
- * @param options - A set of options that can be specified to influence the way in which
5024
- * the event is sent to the associated Event Hub.
5025
- * - `abortSignal` : A signal used to cancel the enqueueEvent operation.
5026
- * - `partitionId` : The partition this set of events will be sent to. If set, `partitionKey` can not be set.
5027
- * - `partitionKey` : A value that is hashed to produce a partition assignment. If set, `partitionId` can not be set.
5028
- * @returns The total number of events that are currently buffered and waiting to be published, across all partitions.
5029
- */
5030
- async enqueueEvent(event, options = {}) {
5031
- if (this._isClosed) {
5032
- throw new Error(`This EventHubBufferedProducerClient has already been closed. Create a new client to enqueue events.`);
5033
- }
5034
- // TODO: Start a loop that queries partition Ids.
5035
- // partition ids can be added to an Event Hub after it's been created.
5036
- if (!this._partitionIds.length) {
5037
- this._partitionIds = await this.getPartitionIds();
5038
- this._partitionAssigner.setPartitionIds(this._partitionIds);
5039
- }
5040
- const partitionId = this._partitionAssigner.assignPartition({
5041
- partitionId: options.partitionId,
5042
- partitionKey: options.partitionKey
5043
- });
5044
- const partitionChannel = this._getPartitionChannel(partitionId);
5045
- await partitionChannel.enqueueEvent(event);
5046
- return this._getTotalBufferedEventsCount();
5047
- }
5048
- /**
5049
- * Enqueues events into the buffer to be published to the Event Hub.
5050
- * If there is no capacity in the buffer when this method is invoked,
5051
- * it will wait for space to become available and ensure that the events
5052
- * have been enqueued.
5053
- *
5054
- * When this call returns, the events have been accepted into the buffer,
5055
- * but it may not have been published yet.
5056
- * Publishing will take place at a nondeterministic point in the future as the buffer is processed.
5057
- *
5058
- * @param events - An array of {@link EventData} or `AmqpAnnotatedMessage`.
5059
- * @param options - A set of options that can be specified to influence the way in which
5060
- * events are sent to the associated Event Hub.
5061
- * - `abortSignal` : A signal used to cancel the enqueueEvents operation.
5062
- * - `partitionId` : The partition this set of events will be sent to. If set, `partitionKey` can not be set.
5063
- * - `partitionKey` : A value that is hashed to produce a partition assignment. If set, `partitionId` can not be set.
5064
- * @returns The total number of events that are currently buffered and waiting to be published, across all partitions.
5065
- */
5066
- async enqueueEvents(events, options = {}) {
5067
- for (const event of events) {
5068
- await this.enqueueEvent(event, options);
5069
- }
5070
- return this._getTotalBufferedEventsCount();
5071
- }
5072
- /**
5073
- * Attempts to publish all events in the buffer immediately.
5074
- * This may result in multiple batches being published,
5075
- * the outcome of each of which will be individually reported by
5076
- * the `onSendEventsSuccessHandler` and `onSendEventsErrorHandler` handlers.
5077
- *
5078
- * @param options - The set of options to apply to the operation call.
5079
- */
5080
- async flush(options = {}) {
5081
- await Promise.all(Array.from(this._partitionChannels.values()).map((channel) => channel.flush(options)));
5082
- }
5083
- /**
5084
- * Provides the Event Hub runtime information.
5085
- * @param options - The set of options to apply to the operation call.
5086
- * @returns A promise that resolves with information about the Event Hub instance.
5087
- * @throws Error if the underlying connection has been closed, create a new EventHubBufferedProducerClient.
5088
- * @throws AbortError if the operation is cancelled via the abortSignal.
5089
- */
5090
- getEventHubProperties(options = {}) {
5091
- return this._producer.getEventHubProperties(options);
5092
- }
5093
- /**
5094
- * Provides the id for each partition associated with the Event Hub.
5095
- * @param options - The set of options to apply to the operation call.
5096
- * @returns A promise that resolves with an Array of strings representing the id for
5097
- * each partition associated with the Event Hub.
5098
- * @throws Error if the underlying connection has been closed, create a new EventHubBufferedProducerClient.
5099
- * @throws AbortError if the operation is cancelled via the abortSignal.
5100
- */
5101
- getPartitionIds(options = {}) {
5102
- return this._producer.getPartitionIds(options);
5103
- }
5104
- /**
5105
- * Provides information about the state of the specified partition.
5106
- * @param partitionId - The id of the partition for which information is required.
5107
- * @param options - The set of options to apply to the operation call.
5108
- * @returns A promise that resolves with information about the state of the partition .
5109
- * @throws Error if the underlying connection has been closed, create a new EventHubBufferedProducerClient.
5110
- * @throws AbortError if the operation is cancelled via the abortSignal.
5111
- */
5112
- getPartitionProperties(partitionId, options = {}) {
5113
- return this._producer.getPartitionProperties(partitionId, options);
5114
- }
5115
- /**
5116
- * Gets the `BatchingPartitionChannel` associated with the partitionId.
5117
- *
5118
- * If one does not exist, it is created.
5119
- */
5120
- _getPartitionChannel(partitionId) {
5121
- var _a;
5122
- const partitionChannel = (_a = this._partitionChannels.get(partitionId)) !== null && _a !== void 0 ? _a : new BatchingPartitionChannel({
5123
- loopAbortSignal: this._abortController.signal,
5124
- maxBufferSize: this._clientOptions.maxEventBufferLengthPerPartition || 1500,
5125
- maxWaitTimeInMs: this._clientOptions.maxWaitTimeInMs || 1000,
5126
- onSendEventsErrorHandler: this._clientOptions.onSendEventsErrorHandler,
5127
- onSendEventsSuccessHandler: this._clientOptions.onSendEventsSuccessHandler,
5128
- partitionId,
5129
- producer: this._producer
5130
- });
5131
- this._partitionChannels.set(partitionId, partitionChannel);
5132
- return partitionChannel;
5133
- }
5134
- /**
5135
- * Returns the total number of buffered events across all partitions.
5136
- */
5137
- _getTotalBufferedEventsCount() {
5138
- let total = 0;
5139
- for (const [_, channel] of this._partitionChannels) {
5140
- total += channel.getCurrentBufferedCount();
5141
- }
5142
- return total;
5143
- }
5144
- }
5145
-
5146
4456
  Object.defineProperty(exports, 'MessagingError', {
5147
4457
  enumerable: true,
5148
4458
  get: function () {
@@ -5155,7 +4465,6 @@ Object.defineProperty(exports, 'RetryMode', {
5155
4465
  return coreAmqp.RetryMode;
5156
4466
  }
5157
4467
  });
5158
- exports.EventHubBufferedProducerClient = EventHubBufferedProducerClient;
5159
4468
  exports.EventHubConsumerClient = EventHubConsumerClient;
5160
4469
  exports.EventHubProducerClient = EventHubProducerClient;
5161
4470
  exports.earliestEventPosition = earliestEventPosition;