diff --git a/sdk/eventhub/event-hubs/README.md b/sdk/eventhub/event-hubs/README.md index 67115b98a3d0..a4ee4c8914f5 100644 --- a/sdk/eventhub/event-hubs/README.md +++ b/sdk/eventhub/event-hubs/README.md @@ -4,7 +4,7 @@ Azure Event Hubs is a highly scalable publish-subscribe service that can ingest The Azure Event Hubs client library allows you to send and receive events in your Node.js application. -[Source code](https://github.com/Azure/azure-sdk-for-js/tree/master/sdk/eventhub/event-hubs) | [Package (npm)](https://www.npmjs.com/package/@azure/event-hubs) | [API Reference Documentation](https://azure.github.io/azure-sdk-for-js/event-hubs/index.html) | [Product documentation](https://azure.microsoft.com/en-us/services/event-hubs/) | [Samples](https://github.com/Azure/azure-sdk-for-js/tree/master/sdk/eventhub/event-hubs/samples) +[Source code](https://github.com/Azure/azure-sdk-for-js/tree/master/sdk/eventhub/event-hubs) | [Package (npm)](https://www.npmjs.com/package/@azure/event-hubs/v/next) | [API Reference Documentation](https://azure.github.io/azure-sdk-for-js/event-hubs/index.html) | [Product documentation](https://azure.microsoft.com/en-us/services/event-hubs/) | [Samples](https://github.com/Azure/azure-sdk-for-js/tree/master/sdk/eventhub/event-hubs/samples) **NOTE**: If you are using version 2.1.0 or lower, then please use the below links instead @@ -218,7 +218,7 @@ operations including checkpointing and load balancing. A checkpoint is meant to represent the last successfully processed event by the user from a particular partition of a consumer group in an Event Hub instance. The `EventProcessor` uses an instance of `PartitionManager` to update checkpoints and to store the relevant information required by the load balancing algorithm. -While for the purposes of getting started you can use the [InMemoryPartitionManager](https://azure.github.io/azure-sdk-for-js/event-hubs/classes/inmemorypartitionmanager.html) that is shipped out of the box from this library, +While for the purposes of getting started you can use the [InMemoryPartitionManager](https://azure.github.io/azure-sdk-for-js/event-hubs/classes/inmemorypartitionmanager.html) that is shipped out of the box from this library, it is recommended to use a peristent store when running in production. Search npm with the prefix `@azure/eventhubs-checkpointstore-` to find packages that support this and use the `PartitionManager` implementation from one such package. @@ -274,17 +274,24 @@ To control the number of events passed to processEvents, use the options argumen ### Use EventHubClient to work with IotHub You can use `EventHubClient` to work with IotHub as well. This is useful for receiving telemetry data of IotHub from the linked EventHub. -Most likely the associated connection string will not have send claims. Hence getting HubRuntimeInfo or PartitionRuntimeInfo and receiving events would be the possible operations. +The associated connection string will not have send claims, +hence sending events is not possible. -- Please notice that we are awaiting on the [createFromIotHubConnectionString](https://azure.github.io/azure-sdk-for-js/event-hubs/classes/eventhubclient.html#createfromiothubconnectionstring) method to get an instance of the EventHubClient. This is different from other static methods on the client. The method talks to the IotHub endpoint to get a redirect error which contains the EventHub endpoint to talk to. It then constructs the right EventHub connection string based on the information in the redirect error and returns an instance of the EventHubClient that you can play with. +- Please notice that the connection string needs to be for an + [Event Hub-compatible endpoint](https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-devguide-messages-read-builtin) + e.g. "Endpoint=sb://my-iothub-namespace-[uid].servicebus.windows.net/;SharedAccessKeyName=my-SA-name;SharedAccessKey=my-SA-key;EntityPath=my-iot-hub-name" ```javascript -const client = await EventHubClient.createFromIotHubConnectionString("connectionString"); +const client = new EventHubClient( + "Endpoint=sb://my-iothub-namespace-[uid].servicebus.windows.net/;SharedAccessKeyName=my-SA-name;SharedAccessKey=my-SA-key;EntityPath=my-iot-hub-name" +); await client.getProperties(); -await client.getPartitionProperties("partitionId"); +// retrieve partitionIds from client.getProperties() or client.getPartitionIds() +const partitionId = "0"; +await client.getPartitionProperties(partitionId); ``` -**Notes:** For scalable and efficient receiving, please take a look at [azure-event-processor-host](https://github.com/Azure/azure-sdk-for-js/tree/master/sdk/eventhub/event-processor-host). The Event Processor host, internally uses the streaming receiver to receive events. +**Notes:** For scalable and efficient receiving, please take a look at [EventProcessor](https://azure.github.io/azure-sdk-for-js/event-hubs/classes/eventprocessor.html). The EventProcessor, internally uses the batched receiver to receive events. ## Troubleshooting diff --git a/sdk/eventhub/event-hubs/changelog.md b/sdk/eventhub/event-hubs/changelog.md index 97e523076c2f..d7c66ef00e8a 100644 --- a/sdk/eventhub/event-hubs/changelog.md +++ b/sdk/eventhub/event-hubs/changelog.md @@ -1,33 +1,55 @@ ### (Date) 5.0.0-preview.4 -- Current implementation of the Partition Manager takes the event hub name, consumer group name and partition id to ensure uniqueness for the checkpoint and ownership. - Since the same event hub name and consumer group name can exist in another namespace, we added `fullyQualifiedNamespace` as well to ensure uniqueness. + +- Current implementation of the Partition Manager takes the event hub name, consumer group name and partition id to ensure uniqueness for the checkpoint and ownership. + Since the same event hub name and consumer group name can exist in another namespace, we added `fullyQualifiedNamespace` as well to ensure uniqueness. ([PR #5153](https://github.com/Azure/azure-sdk-for-js/pull/5153)) +#### Breaking changes + +- Removed the `createFromIotHubConnectionString` method from `EventHubClient`. ([PR #5311](https://github.com/Azure/azure-sdk-for-js/pull/5311)). + Instead, pass an [Event Hubs-compatible connection string](https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-devguide-messages-read-builtin) + when instantiating an `EventHubClient` to read properties or events from an IoT Hub. + + Previously: + + ```javascript + const client = await EventHubClient.createFromIotHubConnectionString(iotConnectionString); + ``` + + Current: + + ```javascript + const client = new EventHubClient(iotEventHubsCompatibleConnectionString); + ``` + ### 2019-09-09 5.0.0-preview.3 #### Features + - Adds load-balancing capabilities to `EventProcessor`. `EventProcesor` will use the data from `PartitionManager` to regulate how many partitions it should read from. -([PR #4839](https://github.com/Azure/azure-sdk-for-js/pull/4839)). + ([PR #4839](https://github.com/Azure/azure-sdk-for-js/pull/4839)). - Adds `lastEnqueuedEventInfo` property on `EventHubConsumer`. When the consumer is created with `trackLastEnqueuedEventInfo` set to `true`, the `lastEnqueuedEventInfo` -field is updated everytime a message is received and provides details about the last enqueued event in the partition the `EventHubConsumer` is reading from. -([PR #5036](https://github.com/Azure/azure-sdk-for-js/pull/5036)) + field is updated everytime a message is received and provides details about the last enqueued event in the partition the `EventHubConsumer` is reading from. + ([PR #5036](https://github.com/Azure/azure-sdk-for-js/pull/5036)) - Received event data will now expose `systemProperties` for message annotations set by the service. ([PR #5008](https://github.com/Azure/azure-sdk-for-js/pull/5008)). - Improved error messages when constructing an `EventHubClient` with an invalid connection string and Event Hub name combo. ([PR #4899](https://github.com/Azure/azure-sdk-for-js/pull/4899)). - Adds client-side type-checking for `EventPosition` static helper methods. ([PR #5052](https://github.com/Azure/azure-sdk-for-js/pull/5052)). #### Breaking changes + - The `PartitionProcessor` interface is now a class with default implementations of `initialize`, `close`, `processEvents`, and `processError`. -([PR #4994](https://github.com/Azure/azure-sdk-for-js/pull/4994)). + ([PR #4994](https://github.com/Azure/azure-sdk-for-js/pull/4994)). - Users should extend the `PartitionProcessor` class and override any of the methods that need custom logic. - All 4 methods now accept `PartitionContext` as the last parameter. - `PartitionContext` contains information about the partition being processed, as well as the `updateCheckpoint` method that can be used to persist a checkpoint. + `PartitionContext` contains information about the partition being processed, as well as the `updateCheckpoint` method that can be used to persist a checkpoint. - The `EventProcessor` constructor was changed to no longer accept a `PartitionProcessorFactory` function that returns a `PartitionProcessor`. -Instead, users should extend the `PartitionProcessor` class and pass the class (not an instance of the class) to the `EventProcessor` constructor. -([PR #4994](https://github.com/Azure/azure-sdk-for-js/pull/4994)). + Instead, users should extend the `PartitionProcessor` class and pass the class (not an instance of the class) to the `EventProcessor` constructor. + ([PR #4994](https://github.com/Azure/azure-sdk-for-js/pull/4994)). ### 2019-08-06 5.0.0-preview.2 #### General + - The sender is refactored to avoid the warning around too may listeners being attached which would occur before if too many send requests were in flight at the same time from the same sender. - The receiver is refactored to allow the same underlying AMQP link to be shared between streaming and batching mode. This results in seamless transition between the three different receive methods on the `EventHubConsumer` - All time related entites have been updated to use milli seconds as the unit of time for consistency. @@ -35,17 +57,20 @@ Instead, users should extend the `PartitionProcessor` class and pass the class ( - The error `OperationTimeoutError` was previously mistakenly classified as an AMQP error which is now corrected. Since this can also be a transient error, it is treated as retryable. #### Publishing events -- Added method `createBatch()` on the `EventHubProducer` to create an `EventDataBatch` that can then be used to add events until the maximum size is reached. + +- Added method `createBatch()` on the `EventHubProducer` to create an `EventDataBatch` that can then be used to add events until the maximum size is reached. - This batch object can then be used in the `send()` method to send all the added events to Event Hubs. - - This allows publishers to build batches without the possibility of encountering the error around the message size exceeding the supported limit when sending events. + - This allows publishers to build batches without the possibility of encountering the error around the message size exceeding the supported limit when sending events. - It also allows publishers with bandwidth concerns to control the size of each batch published. #### Consuming events -- Introduced a new class `EventProcessor` which replaces the older concept of [Event Processor Host](https://www.npmjs.com/package/@azure/event-processor-host). - - This early preview is intended to allow users to test the new design using a single instance of `EventProcessor`. The ability to store checkpoints to a durable store will be added in future updates + +- Introduced a new class `EventProcessor` which replaces the older concept of [Event Processor Host](https://www.npmjs.com/package/@azure/event-processor-host). + - This early preview is intended to allow users to test the new design using a single instance of `EventProcessor`. The ability to store checkpoints to a durable store will be added in future updates #### Retries and timeouts -- The properties on the `RetryOptions` interface have been renamed for ease of use. + +- The properties on the `RetryOptions` interface have been renamed for ease of use. - New property `timeoutInMs` on `RetryOptions` to configure the time to wait before declaring an attempt to have failed with `OperationTimeoutError` error which is retryable. - New properties `mode` and `maxRetryDelayInMs` on `RetryOptions` to configure the exponential retry mode that is now supported @@ -57,128 +82,138 @@ idiomatic to the Javascript ecosystem. The reasons for most of the changes in th For more information, please visit https://aka.ms/azure-sdk-preview1-js #### Breaking changes + - Creating an instance of [EventHubClient](https://azure.github.io/azure-sdk-for-js/event-hubs/classes/eventhubclient.html) -is now done using construtor overloads instead of static helpers. - - If you previously used the `createFromTokenProvider` static helper to provide your own custom token provider, - you will now need to update the provider to follow the new `TokenCredential` interface instead. - - If you previously used the `@azure/ms-rest-nodeauth` library to provide AAD credentials, you will now need to use the new - [@azure/identity](https://www.npmjs.com/package/@azure/identity) library instead. + is now done using construtor overloads instead of static helpers. - If you previously used the `createFromTokenProvider` static helper to provide your own custom token provider, + you will now need to update the provider to follow the new `TokenCredential` interface instead. - If you previously used the `@azure/ms-rest-nodeauth` library to provide AAD credentials, you will now need to use the new + [@azure/identity](https://www.npmjs.com/package/@azure/identity) library instead. - The send methods are moved from the `EventHubClient` class to the new [EventHubProducer](https://azure.github.io/azure-sdk-for-js/event-hubs/classes/eventhubproducer.html) class. - - Use the [createProducer()](https://azure.github.io/azure-sdk-for-js/event-hubs/classes/eventhubclient.html#createproducer) + - Use the [createProducer()](https://azure.github.io/azure-sdk-for-js/event-hubs/classes/eventhubclient.html#createproducer) function on the `EventHubClient` to create an instance of a `EventHubProducer`. - - Each producer represents a dedicated AMQP sender link to Azure Event Hubs. - - The [EventData](https://azure.github.io/azure-sdk-for-js/event-hubs/interfaces/eventdata.html) type used for + - Each producer represents a dedicated AMQP sender link to Azure Event Hubs. + - The [EventData](https://azure.github.io/azure-sdk-for-js/event-hubs/interfaces/eventdata.html) type used for the data being sent only supports a `body` for the content being sent and a `properties` bag to hold any custom metadata you want to send. The properties corresponding to a received event are removed from this type and a separate type [ReceivedEventData](https://azure.github.io/azure-sdk-for-js/event-hubs/interfaces/receivedeventdata.html) is used for received events. - The receive methods are moved from the `EventHubClient` class to the new [EventHubConsumer](https://azure.github.io/azure-sdk-for-js/event-hubs/classes/eventhubconsumer.html) class. - - Use the [createConsumer()](https://azure.github.io/azure-sdk-for-js/event-hubs/classes/eventhubclient.html#createconsumer) + - Use the [createConsumer()](https://azure.github.io/azure-sdk-for-js/event-hubs/classes/eventhubclient.html#createconsumer) function on the `EventHubClient` to create an instance of a `EventHubConsumer`. - - Each consumer represents a dedicated AMQP receiver link to Azure Event Hubs based + - Each consumer represents a dedicated AMQP receiver link to Azure Event Hubs based on the flavor of receive function being used i.e `receiveBatch()` that receives events in a batch vs `receive()` that provides a streaming receiver. - - The static methods `EventPosition.fromStart()` and `EventPosition.fromEnd()` are renamed to `EventPosition.earliest()` and `EventPosition.latest()` respectively. + - The static methods `EventPosition.fromStart()` and `EventPosition.fromEnd()` are renamed to `EventPosition.earliest()` and `EventPosition.latest()` respectively. - Inspecting Event Hub - - The methods `getHubRuntimeInformation()` and `getPartitionInformation()` on the `EventHubClient` are renamed to - [getProperties()](https://azure.github.io/azure-sdk-for-js/event-hubs/classes/eventhubclient.html#getproperties) and + - The methods `getHubRuntimeInformation()` and `getPartitionInformation()` on the `EventHubClient` are renamed to + [getProperties()](https://azure.github.io/azure-sdk-for-js/event-hubs/classes/eventhubclient.html#getproperties) and [getPartitionProperties()](https://azure.github.io/azure-sdk-for-js/event-hubs/classes/eventhubclient.html#getpartitionproperties) respectively. Please refer to the return types of these functions to ensure you are using the right property names. #### New features + - You can now configure retry options that are used to govern retry attempts when a retryable error occurs. These can be -set when creating the `EventHubClient`, `EventHubProducer` and `EventHubConsumer` + set when creating the `EventHubClient`, `EventHubProducer` and `EventHubConsumer` - You can now pass an abort signal to any of the async operations. This signal can be used to cancel such operations. Use -the package [@azure/abort-controller](https://www.npmjs.com/package/@azure/abort-controller) to create such abort signals. + the package [@azure/abort-controller](https://www.npmjs.com/package/@azure/abort-controller) to create such abort signals. - An async iterator is now available to receive events after you create an instance of `EventHubConsumer`. Use the function -[getEventIterator()](https://azure.github.io/azure-sdk-for-js/event-hubs/classes/eventhubconsumer.html#geteventiterator) on the consumer to get a `AsyncIterableIterator` which you can then use in a loop or use it's `next()` function to receive events. + [getEventIterator()](https://azure.github.io/azure-sdk-for-js/event-hubs/classes/eventhubconsumer.html#geteventiterator) on the consumer to get a `AsyncIterableIterator` which you can then use in a loop or use it's `next()` function to receive events. #### Next Steps - Refer to the [API reference documentation](https://azure.github.io/azure-sdk-for-js/event-hubs/index.html) to get -an overview of the entire API surface. + an overview of the entire API surface. - Refer to our [samples](https://github.com/Azure/azure-sdk-for-js/tree/master/sdk/eventhub/event-hubs/samples) to understand the usage of the new APIs. ### 2019-06-10 2.1.0 - Added support for WebSockets. WebSockets enable Event Hubs to work over an HTTP proxy and in environments where the standard AMQP port 5671 is blocked. -Refer to the [websockets](https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/eventhub/event-hubs/samples/websockets.ts) sample to see how to use WebSockets. -- `@types/async-lock` has been moved to being a dependency from a dev-dependency. This fixes the [bug 3240](https://github.com/Azure/azure-sdk-for-js/issues/3240) + Refer to the [websockets](https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/eventhub/event-hubs/samples/websockets.ts) sample to see how to use WebSockets. +- `@types/async-lock` has been moved to being a dependency from a dev-dependency. This fixes the [bug 3240](https://github.com/Azure/azure-sdk-for-js/issues/3240) ### 2019-03-26 2.0.0 #### Breaking Changes -- If you have been using the `createFromAadTokenCredentials` function to create an instance of the -`EventHubClient`, you will now need to use the [@azure/ms-rest-nodeauth](https://www.npmjs.com/package/@azure/ms-rest-nodeauth) -library instead of [ms-rest-azure](https://www.npmjs.com/package/ms-rest-azure) library to create -the credentials that are needed by the `createFromAadTokenCredentials` function. - - Typescript: Replace `import * from "ms-rest-azure";` with `import * from "@azure/ms-rest-nodeauth";` - - Javascript: Replace `require("ms-rest-azure")` with `require("@azure/ms-rest-nodeauth")` -- If you have been passing a non string value in the `partitionKey` property on the message when -sending it using the `EventHubClient`, an error will now be thrown. This property only supports string values. + +- If you have been using the `createFromAadTokenCredentials` function to create an instance of the + `EventHubClient`, you will now need to use the [@azure/ms-rest-nodeauth](https://www.npmjs.com/package/@azure/ms-rest-nodeauth) + library instead of [ms-rest-azure](https://www.npmjs.com/package/ms-rest-azure) library to create + the credentials that are needed by the `createFromAadTokenCredentials` function. - Typescript: Replace `import * from "ms-rest-azure";` with `import * from "@azure/ms-rest-nodeauth";` - Javascript: Replace `require("ms-rest-azure")` with `require("@azure/ms-rest-nodeauth")` +- If you have been passing a non string value in the `partitionKey` property on the message when + sending it using the `EventHubClient`, an error will now be thrown. This property only supports string values. #### Bug fixes and other changes -- A network connection lost error is now treated as retryable error. A new error with name `ConnectionLostError` -is introduced for this scenario which you can see if you enable the [logs](https://github.com/Azure/azure-sdk-for-js/sdk/eventhub/event-hubs/README.md#debug-logs). -- When recovering from an error that caused the underlying AMQP connection to get disconnected, -[rhea](https://github.com/amqp/rhea/issues/205) reconnects all the older AMQP links on the connection -resulting in the below 2 errors in the logs. We now clear rhea's internal map to avoid such reconnections. -We already have code in place to create new AMQP links to resume send/receive operations. - - InvalidOperationError: A link to connection '.....' $cbs node has already been opened. - - UnauthorizedError: Unauthorized access. 'Listen' claim(s) are required to perform this operation. -- Enabled the `esModuleInterop` compilerOption in the `tsconfig.json` file for this library to be -compliant with the [best practices](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-7.html#support-for-import-d-from-cjs-form-commonjs-modules-with---esmoduleinterop). +- A network connection lost error is now treated as retryable error. A new error with name `ConnectionLostError` + is introduced for this scenario which you can see if you enable the [logs](https://github.com/Azure/azure-sdk-for-js/sdk/eventhub/event-hubs/README.md#debug-logs). +- When recovering from an error that caused the underlying AMQP connection to get disconnected, + [rhea](https://github.com/amqp/rhea/issues/205) reconnects all the older AMQP links on the connection + resulting in the below 2 errors in the logs. We now clear rhea's internal map to avoid such reconnections. + We already have code in place to create new AMQP links to resume send/receive operations. - InvalidOperationError: A link to connection '.....' \$cbs node has already been opened. - UnauthorizedError: Unauthorized access. 'Listen' claim(s) are required to perform this operation. +- Enabled the `esModuleInterop` compilerOption in the `tsconfig.json` file for this library to be + compliant with the [best practices](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-7.html#support-for-import-d-from-cjs-form-commonjs-modules-with---esmoduleinterop). ### 2018-12-14 1.0.8 -- Use `isItselfClosed()` instead of `isClosed()` in rhea to correctly determine if the sdk initiated close on receiver/sender. -This ensures that on connection issues like the ECONNRESET error, the receivers get re-connected properly thus fixing the [bug 174](https://github.com/Azure/azure-event-hubs-node/issues/174) + +- Use `isItselfClosed()` instead of `isClosed()` in rhea to correctly determine if the sdk initiated close on receiver/sender. + This ensures that on connection issues like the ECONNRESET error, the receivers get re-connected properly thus fixing the [bug 174](https://github.com/Azure/azure-event-hubs-node/issues/174) ### 2018-10-25 1.0.7 + - Only set `message_id` while sending the message, when provided by caller [PR](https://github.com/Azure/azure-event-hubs-node/pull/169). ### 2018-10-01 1.0.6 + - export `EventHubConnectionConfig` from the library. ### 2018-10-01 1.0.5 + - Moved `lib/amqp-common` to `"@azure/amqp-common"` package and took a dependency on it. - Moved `lib/rhea-promise` to `"rhea-promise"` package and took a dependency on it. - Fixed issues where the private instance of `rhea receiver or sender` were undefined when `*_open` -and `*_close` events happened instantaneously. + and `*_close` events happened instantaneously. ### 2018-09-26 1.0.4 + - update the version of ms-rest-azure to "2.5.9" ### 2018-09-19 1.0.3 + - `EventPosition.fromSequenceNumber()` accepts `0` as a valid argument. - `client.receive()` and `client.receiveBatch()` accept partitionId as a `string | number`. - User's error handler in `client.receive()` will only be notified if the user did not close the receiver and the error is not retryable. ### 2018-09-14 1.0.2 + - `client.getPartitionInformation()` should works as expected when partitionId is of type `number | string`. ### 2018-09-12 1.0.1 + - Stable version of the libray. ### 2018-09-11 0.2.10 + - Added support to provide custom user-agent string that will be appended to the default user agent string. ### 2018-09-11 0.2.9 + - Updated examples and content in README.md ### 2018-08-31 0.2.8 + - Fixed [issue](https://github.com/Azure/azure-event-hubs-node/issues/135) - - Added error handlers to the $management sender/receiver links. + - Added error handlers to the \$management sender/receiver links. - Added error handlers to the amqp session of the $management and $cbs sender/receiver links. - Exported `AadTokenProvider` and `SasTokenProvider` from the client. ### 2018-08-29 0.2.7 + - Improved logging statements to the connection context. - Added timeout to promisifed creation/closing of rhea sender, receiver, session, connection. - Fixed a bug in the EventData deserialization logic by checking for `!= undefined` check rather than the `!` check. - While handling disconnects we retry for 150 times at an interval of 15 seconds as long the error is `retryable`. ### 2018-08-07 0.2.6 + - Improved log statements. - Documented different mechanisms of getting the debug logs in [README](https://github.com/Azure/azure-sdk-for-js/tree/master/eventhub/event-hubs/#debug-logs). - Minimum dependency on `"rhea": "^0.2.18"`. @@ -191,11 +226,13 @@ and `*_close` events happened instantaneously. - Added a new static method `createFromTokenProvider()` on the EventHubClient where customers can provide their own [TokenProvider](https://github.com/Azure/azure-event-hubs-node/blob/master/client/lib/amqp-common/auth/token.ts#L42). ### 2018-07-17 0.2.5 + - Improved log statements - Updated README.md - Updated dependency rhea to "^0.2.16" instead of github dependency. ## 2018-07-16 0.2.4 + - Added support to handle disconnects and link timeout errors. - Fixed client examples link in README. - Updated issue templates @@ -206,44 +243,55 @@ and `*_close` events happened instantaneously. - Replaced crypto with jssha which is browser compatible ## 2018-06-13 0.2.3 + - Minor doc fixes and sample updates. - Add a listener for the disconnected event after opening the connection. ## 2018-05-23 0.2.2 + - Fixed the partitionkey issue while sending events. #73. - Bumped the minimum dependency on rhea to 0.2.13. This gives us type definitions for rhea. - rpc.open() returns the connection object. This makes it easy to extract common functionality to a -separate library. + separate library. ## 2018-05-09 0.2.1 + - Added support to create EventHubClient from an IotHub connectionstring. The following can be done + ```javascript -const client = await EventHubClient.createFromIotHubConnectionString(process.env.IOTHUB_CONNECTION_STRING); +const client = await EventHubClient.createFromIotHubConnectionString( + process.env.IOTHUB_CONNECTION_STRING +); ``` + - Internal design changes: - ManagementClient also does cbs auth before making the management request. - EventHubSender, EventHubReceiver, ManagementClient inherit from a base class ClientEntity. - Moved opening the connection to CbSClient as that is the first thing that should happen after opening the connection. This reduces calls to `rpc.open()` all over the sdk and puts them at one place in the `init()` method on the CbsClient. ## 2018-05-02 0.2.0 + - Added functionality to encode/decode the messages sent and received. - Created an options object in the `client.createFromConnectionString()` and the `EventHubClient` constructor. This is a breaking change. However moving to an options object design reduces the chances of breaking changes in the future. - This options object will: - - have the existing optional `tokenProvider` property - - and a new an optional property named `dataTransformer`. You can provide your own transformer. If not provided then we will use the [DefaultDataTransformer](./client/lib/dataTransformer.ts). This should be applicable for majority of the scenarios and will ensure that messages are interoperable between different Azure services. It fixes issue #60. + This options object will: +- have the existing optional `tokenProvider` property +- and a new an optional property named `dataTransformer`. You can provide your own transformer. If not provided then we will use the [DefaultDataTransformer](./client/lib/dataTransformer.ts). This should be applicable for majority of the scenarios and will ensure that messages are interoperable between different Azure services. It fixes issue #60. ## 2018-04-26 0.1.2 + - Added missing dependency for `uuid` package and nit fixes in the README.md ## 2018-04-24 0.1.1 + - Changing `client.receiveOnMessage()` to `client.receive()` as that is a better naming convention and is in sync with other language sdks. ## 2018-04-23 0.1.0 + - Previously we were depending on [amqp10](https://npmjs.com/package/amqp10) package for the amqp protocol. Moving forward we will be depending on [rhea](https://npmjs.com/package/rhea). - The public facing API of this library has major breaking changes from the previous version 0.0.8. Please take a look at the [Readme](./README.md) and the [samples](./samples) directory for detailed samples. - Removed the need to say `client.open.then()`. First call to create a sender, receiver or get metadata about the hub or partition will establish the AMQP connection. - Added support to authenticate via Service Principal credentials, MSITokenCredentials, DeviceTokenCredentials. - - This should make it easy for customers to login once using the above mentioned credentials, + - This should make it easy for customers to login once using the above mentioned credentials, - Create the EventHubs infrastructure on the Azure management/control plane programmatically using (azure-arm-eventhubs) package over HTTPS prtocol. - Use the same credentials to send and receive messages to the EventHub using this library over AMQP protocol. - Provided a promise based API to create senders/receivers off the `EventHubClient`. @@ -254,12 +302,15 @@ const client = await EventHubClient.createFromIotHubConnectionString(process.env - Added proper TypeScript type definitions to the library that improves the intellisense experience for our customers. ## 2017-05-18 0.0.8 + - Fixed a race condition within the AMQP redirection code when using an IoT Hub connection string. - Disabled auto-retry of AMQP connections in amqp10 since the current client is not built to handle them and fails when retrying. ## 2017-03-31 0.0.7 + - Pulled changes for #14 and #20/#21. - Special thanks to @kurtb and @ali92hm for their contributions! ## 2017-01-13 0.0.6 + - Added support for message properties in the EventData structure. diff --git a/sdk/eventhub/event-hubs/review/event-hubs.api.md b/sdk/eventhub/event-hubs/review/event-hubs.api.md index 22f05590439c..33ae306358bf 100644 --- a/sdk/eventhub/event-hubs/review/event-hubs.api.md +++ b/sdk/eventhub/event-hubs/review/event-hubs.api.md @@ -90,7 +90,6 @@ export class EventHubClient { constructor(connectionString: string, eventHubName: string, options?: EventHubClientOptions); close(): Promise; createConsumer(consumerGroup: string, partitionId: string, eventPosition: EventPosition, options?: EventHubConsumerOptions): EventHubConsumer; - static createFromIotHubConnectionString(iothubConnectionString: string, options?: EventHubClientOptions): Promise; createProducer(options?: EventHubProducerOptions): EventHubProducer; static defaultConsumerGroupName: string; readonly eventHubName: string; diff --git a/sdk/eventhub/event-hubs/samples/useWithIotHub.ts b/sdk/eventhub/event-hubs/samples/useWithIotHub.ts index 40fc4f7e449c..37aa8d1a70e3 100644 --- a/sdk/eventhub/event-hubs/samples/useWithIotHub.ts +++ b/sdk/eventhub/event-hubs/samples/useWithIotHub.ts @@ -6,17 +6,20 @@ */ import { EventHubClient } from "@azure/event-hubs"; -// Define IoT Hub connection string here +// Define IoT Hub Event Hubs-compatible connection string here. +// To find the correct connection string to use, visit: +// https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-devguide-messages-read-builtin const connectionString = ""; async function main(): Promise { - const client = await EventHubClient.createFromIotHubConnectionString(connectionString); + const client = new EventHubClient(connectionString); /* - Refer to other samples, and place your code here to send/receive events using the above client + Refer to other samples, and place your code here to receive events using the above client. + Please note that send operations are not supported when this client is used against an IotHub instance */ await client.close(); } -main().catch(err => { +main().catch((err) => { console.log("Error occurred: ", err); }); diff --git a/sdk/eventhub/event-hubs/src/eventHubClient.ts b/sdk/eventhub/event-hubs/src/eventHubClient.ts index c0cb876821b5..2552aa9862a4 100644 --- a/sdk/eventhub/event-hubs/src/eventHubClient.ts +++ b/sdk/eventhub/event-hubs/src/eventHubClient.ts @@ -20,7 +20,6 @@ import { ConnectionContext } from "./connectionContext"; import { PartitionProperties, EventHubProperties } from "./managementClient"; import { EventPosition } from "./eventPosition"; -import { IotHubClient } from "./iothub/iothubClient"; import { AbortSignalLike } from "@azure/abort-controller"; import { EventHubProducer } from "./sender"; import { EventHubConsumer } from "./receiver"; @@ -694,29 +693,6 @@ export class EventHubClient { } } - /** - * Creates an EventHubClient from connection string. - * @param iothubConnectionString - Connection string of the form 'HostName=iot-host-name;SharedAccessKeyName=my-SA-name;SharedAccessKey=my-SA-key'. - * @param [options] Options that can be provided during client creation. - * @returns - Promise. - * @throws {Error} Thrown if the iothubConnectionString is not provided as a string. - */ - static async createFromIotHubConnectionString( - iothubConnectionString: string, - options?: EventHubClientOptions - ): Promise { - if ( - !iothubConnectionString || - (iothubConnectionString && typeof iothubConnectionString !== "string") - ) { - throw new Error("'connectionString' is a required parameter and must be of type: 'string'."); - } - const connectionString = await new IotHubClient( - iothubConnectionString - ).getEventHubConnectionString(); - return new EventHubClient(connectionString, options); - } - /** * @property * The name of the default consumer group in the Event Hubs service. diff --git a/sdk/eventhub/event-hubs/src/iothub/iothubClient.ts b/sdk/eventhub/event-hubs/src/iothub/iothubClient.ts deleted file mode 100644 index 2cd4ffb15568..000000000000 --- a/sdk/eventhub/event-hubs/src/iothub/iothubClient.ts +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -import { translate, MessagingError, IotSharedKeyCredential } from "@azure/core-amqp"; -import { IotHubConnectionConfig } from "@azure/core-amqp"; -import { ConnectionContext, ConnectionContextOptions } from "../connectionContext"; -import * as log from "../log"; - -/** - * @interface ParsedRedirectError - * @ignore - */ -export interface ParsedRedirectError { - endpoint: string; - entityPath: string; -} -/** - * @interface EHConfig - * @ignore - */ -export interface EHConfig extends ParsedRedirectError { - sharedAccessKey: string; - sharedAccessKeyName: string; -} -/** - * @class IotHubClient - * @ignore - */ -export class IotHubClient { - /** - * @property connectionString the IotHub connection string. - */ - connectionString: string; - - constructor(connectionString: string) { - this.connectionString = connectionString; - } - /** - * Constructs the EventHub connection string by catching the redirect error and parsing the error - * information. - * @ignore - * @param [options] optional parameters to be provided while creating - * the connection context. - * @returns Promise - */ - async getEventHubConnectionString(options?: ConnectionContextOptions): Promise { - const iothubconfig = IotHubConnectionConfig.create(this.connectionString); - const config = IotHubConnectionConfig.convertToEventHubConnectionConfig(iothubconfig); - let result: string = ""; - if (!options) options = {}; - const tokenProvider = new IotSharedKeyCredential( - config.sharedAccessKeyName, - config.sharedAccessKey - ); - options.managementSessionAddress = `/messages/events/$management`; - const context = ConnectionContext.create(config, tokenProvider, options); - try { - log.iotClient( - "Getting the hub runtime info from the iothub connection string to get the redirect error." - ); - await context.managementSession!.getHubRuntimeInformation(); - } catch (err) { - const error = translate(err); - log.error("IotHubClient received the error: %O", error); - const parsedInfo: ParsedRedirectError = this._parseRedirectError(err); - log.error("Parsed info from redirect error is: %O", parsedInfo); - result = this._buildConnectionString({ - sharedAccessKey: config.sharedAccessKey, - sharedAccessKeyName: config.sharedAccessKeyName, - endpoint: parsedInfo.endpoint, - entityPath: parsedInfo.entityPath - }); - } - log.iotClient("The EventHub ConnectionString is: '%s'.", result); - await this.close(context); - return result; - } - - /** - * Closes the AMQP connection to the Event Hub for this client, - * returning a promise that will be resolved when disconnection is completed. - * @ignore - * @returns - */ - async close(context: ConnectionContext): Promise { - try { - if (context.connection.isOpen()) { - log.iotClient("Closing the IotHubClient connection..."); - // Close the cbs session; - await context.cbsSession.close(); - log.iotClient("IotHub cbs session closed."); - // Close the management session - await context.managementSession!.close(); - log.iotClient("IotHub management client closed."); - await context.connection.close(); - log.iotClient( - "Closed the amqp connection '%s' on the iothub client.", - context.connectionId - ); - } - } catch (err) { - const msg = `An error occurred while closing the connection "${context.connectionId}": ${err.stack}`; - log.error(msg); - } - } - - private _parseRedirectError(error: MessagingError): ParsedRedirectError { - if (!error) { - throw new Error("'error' is a required parameter and must be of type 'object'."); - } - if (error.name !== "LinkRedirectError" || !error.info) { - throw error; - } - if (!error.info.hostname || !error.info.address) { - const msg = `The received redirect error from IotHub is malformed. ${error.stack}\n${error.info}`; - throw new Error(msg); - } - - const address: string = error.info.address; - const parsedResult = address.match(/5671\/(.*)\/\$management/i); - if (parsedResult == undefined || (parsedResult && parsedResult[1] == undefined)) { - const msg = - `Cannot parse the EventHub name from the given address: ${address} in the error: ` + - `${error.stack}\n${JSON.stringify(error.info)}.\nThe parsed result is: ${JSON.stringify( - parsedResult - )}.`; - throw new Error(msg); - } - - return { - endpoint: error.info.hostname, - entityPath: parsedResult[1] - }; - } - - private _buildConnectionString(config: EHConfig): string { - const parts = new Map(); - parts.set("Endpoint", `sb://${config.endpoint}/`); - parts.set("SharedAccessKeyName", config.sharedAccessKeyName); - parts.set("SharedAccessKey", config.sharedAccessKey); - parts.set("EntityPath", config.entityPath); - return Array.from(parts) - .map((part) => `${part[0]}=${part[1]}`) - .join(";"); - } -} diff --git a/sdk/eventhub/event-hubs/test/iothub.spec.ts b/sdk/eventhub/event-hubs/test/iothub.spec.ts index 3813823b4971..71880b504bde 100644 --- a/sdk/eventhub/event-hubs/test/iothub.spec.ts +++ b/sdk/eventhub/event-hubs/test/iothub.spec.ts @@ -11,8 +11,10 @@ import { EventHubClient, EventPosition } from "../src"; import { EnvVarKeys, getEnvVars } from "./utils/testUtils"; const env = getEnvVars(); -describe("EventHub Client with iothub connection string ", function(): void { - const service = { connectionString: env[EnvVarKeys.IOTHUB_CONNECTION_STRING] }; +describe("EventHub Client with iothub connection string #RunnableInBrowser", function(): void { + const service = { + connectionString: (env[EnvVarKeys.IOTHUB_CONNECTION_STRING] as string) || "" + }; let client: EventHubClient; before("validate environment", async function(): Promise { should.exist( @@ -29,7 +31,7 @@ describe("EventHub Client with iothub connection string ", function(): void { }); it("should be able to get hub runtime info", async function(): Promise { - client = await EventHubClient.createFromIotHubConnectionString(service.connectionString!); + client = new EventHubClient(service.connectionString); const runtimeInfo = await client.getProperties(); debug(">>> RuntimeInfo: ", runtimeInfo); should.exist(runtimeInfo, `RuntimeIno does not exist. Found ${runtimeInfo}`); @@ -41,7 +43,7 @@ describe("EventHub Client with iothub connection string ", function(): void { }); it("should be able to receive messages from the event hub", async function(): Promise { - client = await EventHubClient.createFromIotHubConnectionString(service.connectionString!); + client = new EventHubClient(service.connectionString); const receiver = client.createConsumer( EventHubClient.defaultConsumerGroupName, "0",