From 4829f3aab1cc8405a95fdd716ac4be211012f221 Mon Sep 17 00:00:00 2001 From: Jesse Squire Date: Tue, 19 Jan 2021 15:10:40 -0500 Subject: [PATCH] [Event Hubs Client] February Release Documentation The focus of these changes is updating the samples, README, and change log to reflect the February milestone release. --- .../CHANGELOG.md | 23 +++- .../Sample02_EventProcessorConfiguration.md | 96 +++++++++++++ .../src/EventProcessorClientOptions.cs | 7 + ...02_EventProcessorConfigurationLiveTests.cs | 126 ++++++++++++++++++ .../Azure.Messaging.EventHubs/CHANGELOG.md | 27 +++- .../samples/README.md | 2 +- .../samples/Sample02_EventHubsClients.md | 19 +++ .../src/Azure.Messaging.EventHubs.csproj | 2 +- .../src/Producer/EventDataBatch.cs | 6 + .../Sample02_EventHubsClientsLiveTests.cs | 45 ++++--- 10 files changed, 334 insertions(+), 19 deletions(-) mode change 100644 => 100755 sdk/eventhub/Azure.Messaging.EventHubs.Processor/samples/Sample02_EventProcessorConfiguration.md diff --git a/sdk/eventhub/Azure.Messaging.EventHubs.Processor/CHANGELOG.md b/sdk/eventhub/Azure.Messaging.EventHubs.Processor/CHANGELOG.md index f2749dae6fc2..1249a09b8ba0 100755 --- a/sdk/eventhub/Azure.Messaging.EventHubs.Processor/CHANGELOG.md +++ b/sdk/eventhub/Azure.Messaging.EventHubs.Processor/CHANGELOG.md @@ -1,7 +1,26 @@ # Release History -## 5.3.0-beta.5 (Unreleased) +## 5.3.0-beta.5 (2021-02-09) +### Changes + +#### New Features + +- Additional options for tuning load balancing have been added to the `EventProcessorClientOptions`. + +- It is now possible to specify a custom endpoint to use for establishing the connection to the Event Hubs service in the `EventHubConnectionOptions` for the processor. + +- Interactions with Blob Storage have been tuned for better performance and more efficient resource use. This will also improve start-up time, especially when using the `Greedy` load balancing strategy. + +- Errors occurring in the Event Hubs service or active transport are now preserved in full and propagated as an inner exception; this will provide deeper context for diagnosing and troubleshooting exceptions. + +- Documentation used for auto-completion via Intellisense and other tools has been enhanced in many areas, addressing gaps and commonly asked questions. + +#### Key Bug Fixes + +- Upgraded the `Microsoft.Azure.Amqp` library to resolve crashes occurring in .NET 5. + +- The calculation for authorization token expiration has been fixed, resulting in fewer token refreshes and network requests. ## 5.3.0-beta.4 (2020-11-10) @@ -15,6 +34,8 @@ #### Key Bug Fixes +- Upgraded the `Microsoft.Azure.Amqp` library to resolve crashes occurring in .NET 5. + - The calculation for authorization token expiration has been fixed, resulting in fewer token refreshes and network requests. ## 5.3.0-beta.3 (2020-09-30) diff --git a/sdk/eventhub/Azure.Messaging.EventHubs.Processor/samples/Sample02_EventProcessorConfiguration.md b/sdk/eventhub/Azure.Messaging.EventHubs.Processor/samples/Sample02_EventProcessorConfiguration.md old mode 100644 new mode 100755 index 7945b7e4a475..1a68825eee38 --- a/sdk/eventhub/Azure.Messaging.EventHubs.Processor/samples/Sample02_EventProcessorConfiguration.md +++ b/sdk/eventhub/Azure.Messaging.EventHubs.Processor/samples/Sample02_EventProcessorConfiguration.md @@ -4,6 +4,73 @@ The `EventProcessorClient` supports a set of options to configure many aspects o To begin, please ensure that you're familiar with the items discussed in the [Getting started](https://github.com/Azure/azure-sdk-for-net/tree/master/sdk/eventhub/Azure.Messaging.EventHubs.Processor/samples#getting-started) section of the README, and have the prerequisites and connection string information available. +## Influencing load balancing behavior + +To scale event processing, you can run multiple instances of the `EventProcessorClient` and they will coordinate to balance work between them. The responsibility for processing is distributed among each of the active processors configured to read from the same Event Hub and using the same consumer group. To balance work, each active `EventProcessorClient` instance will assume responsibility for processing a set of Event Hub partitions, referred to as "owning" the partitions. The processors collaborate on ownership using storage as a central point of coordination. + +While an `EventProcessorClient` is running, it will periodically perform a load balancing cycle in which it audits its own health and inspects the current state of collaboration with other processors. As part of that cycle, it will refresh the timestamp on an ownership record for each partition that it owns. These ownership records help to ensure that each `EventProcessorClient` understands how to maintain its fair share of partitions. + +There are several configuration options that can be used together to influence the behavior of load balancing, allowing you to tune it for the specific needs of your application. + +### Load balancing strategy + +This controls the approach that the `EventProcessorClient` will use to make decisions about how aggressively to request partition ownership; this is most impactful during the initial startup or when recovering from a crash. More information on the strategies available can be found in the [documentation](https://docs.microsoft.com/dotnet/api/azure.messaging.eventhubs.processor.loadbalancingstrategy). + +```C# Snippet:EventHubs_Processor_Sample02_LoadBalancingStrategy +var storageConnectionString = "<< CONNECTION STRING FOR THE STORAGE ACCOUNT >>"; +var blobContainerName = "<< NAME OF THE BLOB CONTAINER >>"; + +var eventHubsConnectionString = "<< CONNECTION STRING FOR THE EVENT HUBS NAMESPACE >>"; +var eventHubName = "<< NAME OF THE EVENT HUB >>"; +var consumerGroup = "<< NAME OF THE EVENT HUB CONSUMER GROUP >>"; + +var processorOptions = new EventProcessorClientOptions +{ + LoadBalancingStrategy = LoadBalancingStrategy.Greedy +}; + +var storageClient = new BlobContainerClient( + storageConnectionString, + blobContainerName); + +var processor = new EventProcessorClient( + storageClient, + consumerGroup, + eventHubsConnectionString, + eventHubName, + processorOptions); +``` + +### Load balancing intervals + +There are two intervals considered during load balancing which can influence its behavior. The `LoadBalancingInterval` controls how frequently a load balancing cycle is run. During the load balancing cycle, the `EventProcessorClient` will attempt to refresh its ownership record for each partition that it owns. The `PartitionOwnershipExpirationInterval` controls how long an ownership record is considered valid. If the processor does not update an ownership record before this interval elapses, the partition represented by this record is considered unowned and is eligible to be claimed by another processor. + +```C# Snippet:EventHubs_Processor_Sample02_LoadBalancingIntervals +var storageConnectionString = "<< CONNECTION STRING FOR THE STORAGE ACCOUNT >>"; +var blobContainerName = "<< NAME OF THE BLOB CONTAINER >>"; + +var eventHubsConnectionString = "<< CONNECTION STRING FOR THE EVENT HUBS NAMESPACE >>"; +var eventHubName = "<< NAME OF THE EVENT HUB >>"; +var consumerGroup = "<< NAME OF THE EVENT HUB CONSUMER GROUP >>"; + +var processorOptions = new EventProcessorClientOptions +{ + LoadBalancingUpdateInterval = TimeSpan.FromSeconds(10), + PartitionOwnershipExpirationInterval = TimeSpan.FromSeconds(30) +}; + +var storageClient = new BlobContainerClient( + storageConnectionString, + blobContainerName); + +var processor = new EventProcessorClient( + storageClient, + consumerGroup, + eventHubsConnectionString, + eventHubName, + processorOptions); +``` + ## Using web sockets Communication with the Event Hubs service can be configured by adjusting the `EventHubConfigurationOptions` that are exposed by the `ConnectionOptions` member of a client options type. By default, the `EventProcessorClient` communicates using the AMQP protocol over TCP. Some application host environments prefer to restrict raw TCP socket use, especially in many enterprise or VPN scenarios. In these environments, or when a proxy is in use, communication with the Event Hubs service can make use of web sockets by configuring the client's connection settings. @@ -133,6 +200,35 @@ var options = new EventHubConnectionOptions }; ``` +### Specifying a custom endpoint address + +Connections to the Azure Event Hubs service are made using the fully qualified namespace assigned to the Event Hubs namespace as the connection endpoint address. Because the Event Hubs service uses the endpoint address to locate the corresponding resources, it isn't possible to specify a custom address in the connection string or as the fully qualified namespace. + +However, a custom address is required for proper routing by some environments, such as those using unconventional proxy configurations or certain configurations of an Express Route circuit. To support these scenarios, a custom endpoint address may be specified as part of the connection options. This custom address will take precedence for establishing the connection to the Event Hubs service. + +```C# Snippet:EventHubs_Processor_Sample02_ConnectionOptionsCustomEndpoint +var storageConnectionString = "<< CONNECTION STRING FOR THE STORAGE ACCOUNT >>"; +var blobContainerName = "<< NAME OF THE BLOB CONTAINER >>"; + +var eventHubsConnectionString = "<< CONNECTION STRING FOR THE EVENT HUBS NAMESPACE >>"; +var eventHubName = "<< NAME OF THE EVENT HUB >>"; +var consumerGroup = "<< NAME OF THE EVENT HUB CONSUMER GROUP >>"; + +var processorOptions = new EventProcessorClientOptions(); +processorOptions.ConnectionOptions.CustomEndpointAddress = new Uri("amqps://app-gateway.mycompany.com"); + +var storageClient = new BlobContainerClient( + storageConnectionString, + blobContainerName); + +var processor = new EventProcessorClient( + storageClient, + consumerGroup, + eventHubsConnectionString, + eventHubName, + processorOptions); +``` + ### Configuring the client retry thresholds The built-in retry policy offers an implementation for an exponential back-off strategy by default, as this provides a good balance between making forward progress and allowing for transient issues that may take some time to resolve. The built-in policy also offers a fixed strategy for those cases where your application requires that you have a deterministic understanding of how long an operation may take. diff --git a/sdk/eventhub/Azure.Messaging.EventHubs.Processor/src/EventProcessorClientOptions.cs b/sdk/eventhub/Azure.Messaging.EventHubs.Processor/src/EventProcessorClientOptions.cs index 8da27c0cec62..8d6e9203a6ad 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs.Processor/src/EventProcessorClientOptions.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs.Processor/src/EventProcessorClientOptions.cs @@ -244,6 +244,13 @@ public TimeSpan LoadBalancingUpdateInterval /// /// If not specified, an ownership interval of 30 seconds will be assumed. /// + /// + /// As a general guideline, it is advised that this value be greater than the configured + /// by at least a factor of two. It is recommended that + /// this be a factor of three or more, unless there are application scenarios that require more + /// aggressive ownership expiration. + /// + /// public TimeSpan PartitionOwnershipExpirationInterval { get => _partitionOwnershipExpirationInterval; diff --git a/sdk/eventhub/Azure.Messaging.EventHubs.Processor/tests/Snippets/Sample02_EventProcessorConfigurationLiveTests.cs b/sdk/eventhub/Azure.Messaging.EventHubs.Processor/tests/Snippets/Sample02_EventProcessorConfigurationLiveTests.cs index f0c357f1958d..88744e49a0da 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs.Processor/tests/Snippets/Sample02_EventProcessorConfigurationLiveTests.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs.Processor/tests/Snippets/Sample02_EventProcessorConfigurationLiveTests.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Net; using System.Threading.Tasks; +using Azure.Messaging.EventHubs.Processor; using Azure.Messaging.EventHubs.Processor.Tests; using Azure.Storage.Blobs; using NUnit.Framework; @@ -23,6 +24,91 @@ namespace Azure.Messaging.EventHubs.Tests.Snippets [SuppressMessage("Style", "IDE0059:Unnecessary assignment of a value", Justification = "Example assignments needed for snippet output content.")] public class Sample02_EventProcessorConfigurationLiveTests { + /// + /// Performs basic smoke test validation of the contained snippet. + /// + /// + [Test] + public void ConfigureLoadBalancingStrategy() + { + #region Snippet:EventHubs_Processor_Sample02_LoadBalancingStrategy + + var storageConnectionString = "<< CONNECTION STRING FOR THE STORAGE ACCOUNT >>"; + var blobContainerName = "<< NAME OF THE BLOB CONTAINER >>"; + /*@@*/ + /*@@*/ storageConnectionString = StorageTestEnvironment.Instance.StorageConnectionString; + /*@@*/ blobContainerName = "not-real"; + + var eventHubsConnectionString = "<< CONNECTION STRING FOR THE EVENT HUBS NAMESPACE >>"; + var eventHubName = "<< NAME OF THE EVENT HUB >>"; + var consumerGroup = "<< NAME OF THE EVENT HUB CONSUMER GROUP >>"; + /*@@*/ + /*@@*/ eventHubsConnectionString = EventHubsTestEnvironment.Instance.EventHubsConnectionString; + /*@@*/ eventHubName = "fakeHub"; + /*@@*/ consumerGroup = "fakeConsumer"; + + var processorOptions = new EventProcessorClientOptions + { + LoadBalancingStrategy = LoadBalancingStrategy.Greedy + }; + + var storageClient = new BlobContainerClient( + storageConnectionString, + blobContainerName); + + var processor = new EventProcessorClient( + storageClient, + consumerGroup, + eventHubsConnectionString, + eventHubName, + processorOptions); + + #endregion + } + + /// + /// Performs basic smoke test validation of the contained snippet. + /// + /// + [Test] + public void ConfigureLoadBalancingIntervals() + { + #region Snippet:EventHubs_Processor_Sample02_LoadBalancingIntervals + + var storageConnectionString = "<< CONNECTION STRING FOR THE STORAGE ACCOUNT >>"; + var blobContainerName = "<< NAME OF THE BLOB CONTAINER >>"; + /*@@*/ + /*@@*/ storageConnectionString = StorageTestEnvironment.Instance.StorageConnectionString; + /*@@*/ blobContainerName = "not-real"; + + var eventHubsConnectionString = "<< CONNECTION STRING FOR THE EVENT HUBS NAMESPACE >>"; + var eventHubName = "<< NAME OF THE EVENT HUB >>"; + var consumerGroup = "<< NAME OF THE EVENT HUB CONSUMER GROUP >>"; + /*@@*/ + /*@@*/ eventHubsConnectionString = EventHubsTestEnvironment.Instance.EventHubsConnectionString; + /*@@*/ eventHubName = "fakeHub"; + /*@@*/ consumerGroup = "fakeConsumer"; + + var processorOptions = new EventProcessorClientOptions + { + LoadBalancingUpdateInterval = TimeSpan.FromSeconds(10), + PartitionOwnershipExpirationInterval = TimeSpan.FromSeconds(30) + }; + + var storageClient = new BlobContainerClient( + storageConnectionString, + blobContainerName); + + var processor = new EventProcessorClient( + storageClient, + consumerGroup, + eventHubsConnectionString, + eventHubName, + processorOptions); + + #endregion + } + /// /// Performs basic smoke test validation of the contained snippet. /// @@ -195,6 +281,46 @@ public void ConfigureProxyByProperty() #endregion } + /// + /// Performs basic smoke test validation of the contained snippet. + /// + /// + [Test] + public void ConfigureCustomEndpointAddress() + { + #region Snippet:EventHubs_Processor_Sample02_ConnectionOptionsCustomEndpoint + + var storageConnectionString = "<< CONNECTION STRING FOR THE STORAGE ACCOUNT >>"; + var blobContainerName = "<< NAME OF THE BLOB CONTAINER >>"; + /*@@*/ + /*@@*/ storageConnectionString = StorageTestEnvironment.Instance.StorageConnectionString; + /*@@*/ blobContainerName = "not-real"; + + var eventHubsConnectionString = "<< CONNECTION STRING FOR THE EVENT HUBS NAMESPACE >>"; + var eventHubName = "<< NAME OF THE EVENT HUB >>"; + var consumerGroup = "<< NAME OF THE EVENT HUB CONSUMER GROUP >>"; + /*@@*/ + /*@@*/ eventHubsConnectionString = EventHubsTestEnvironment.Instance.EventHubsConnectionString; + /*@@*/ eventHubName = "fakeHub"; + /*@@*/ consumerGroup = "fakeConsumer"; + + var processorOptions = new EventProcessorClientOptions(); + processorOptions.ConnectionOptions.CustomEndpointAddress = new Uri("amqps://app-gateway.mycompany.com"); + + var storageClient = new BlobContainerClient( + storageConnectionString, + blobContainerName); + + var processor = new EventProcessorClient( + storageClient, + consumerGroup, + eventHubsConnectionString, + eventHubName, + processorOptions); + + #endregion + } + /// /// Performs basic smoke test validation of the contained snippet. /// diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/CHANGELOG.md b/sdk/eventhub/Azure.Messaging.EventHubs/CHANGELOG.md index 7f6788569260..c2a89e63f8b1 100755 --- a/sdk/eventhub/Azure.Messaging.EventHubs/CHANGELOG.md +++ b/sdk/eventhub/Azure.Messaging.EventHubs/CHANGELOG.md @@ -1,7 +1,32 @@ # Release History -## 5.3.0-beta.5 (Unreleased) +## 5.3.0 (2021-02-09) +### Changes + +#### New Features + +- Connection strings can now be parsed into their key/value pairs using the `EventHubsConnectionStringProperties` class. + +- The body of an event has been moved to the `EventData.EventBody` property and makes use of the new `BinaryData` type. To preserve backwards compatibility, the existing `EventData.Body` property has been preserved with the current semantics. + +- It is now possible to specify a custom endpoint to use for establishing the connection to the Event Hubs service in the `EventHubConnectionOptions` used by each of the clients. + +- Errors occurring in the Event Hubs service or active transport are now preserved in full and propagated as an inner exception; this will provide deeper context for diagnosing and troubleshooting exceptions. + +- The `EventHubsModelFactory` has been introduced to provide a single point for creation of Event Hubs model types to assist with mocking and testing. + +- Documentation used for auto-completion via Intellisense and other tools has been enhanced in many areas, addressing gaps and commonly asked questions. + +#### Key Bug Fixes + +- Upgraded the `Microsoft.Azure.Amqp` library to resolve crashes occurring in .NET 5. + +- The `EventHubsException.ToString` result will now properly follow the format of other .NET exception output. + +- Signaling the cancellation token will no longer cause the `SendAsync` method of the `EventHubProducerClient` to ignore the result of the service operation if publishing has already completed. + +- The calculation for authorization token expiration has been fixed, resulting in fewer token refreshes and network requests. ## 5.3.0-beta.4 (2020-11-10) diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/samples/README.md b/sdk/eventhub/Azure.Messaging.EventHubs/samples/README.md index 60673df064e4..3bcd614a61aa 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs/samples/README.md +++ b/sdk/eventhub/Azure.Messaging.EventHubs/samples/README.md @@ -40,7 +40,7 @@ To quickly create a basic set of Event Hubs resources in Azure and to receive a Install the Azure Event Hubs client library for .NET with [NuGet](https://www.nuget.org/): ```PowerShell -dotnet add package Azure.Messaging.EventHubs --version 5.3.0-beta.4 +dotnet add package Azure.Messaging.EventHubs ``` ### Authenticate the client diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/samples/Sample02_EventHubsClients.md b/sdk/eventhub/Azure.Messaging.EventHubs/samples/Sample02_EventHubsClients.md index fb6451da6782..cd110efc363d 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs/samples/Sample02_EventHubsClients.md +++ b/sdk/eventhub/Azure.Messaging.EventHubs/samples/Sample02_EventHubsClients.md @@ -121,6 +121,25 @@ var options = new EventHubConnectionOptions }; ``` +### Specifying a custom endpoint address + +Connections to the Azure Event Hubs service are made using the fully qualified namespace assigned to the Event Hubs namespace as the connection endpoint address. Because the Event Hubs service uses the endpoint address to locate the corresponding resources, it isn't possible to specify another address in the connection string or as the fully qualified namespace. + +Some environments using unconventional proxy configurations or with certain configurations of an Express Route circuit require a custom address be used for proper routing, leaving are unable to connect from their on-premises network to the Event Hubs service using the assigned endpoint address. To support these scenarios, a custom endpoint address may be specified as part of the connection options. This custom address will take precedence for establishing the connection to the Event Hubs service. + +```C# Snippet:EventHubs_Sample02_ConnectionOptionsCustomEndpoint +var connectionString = "<< CONNECTION STRING FOR THE EVENT HUBS NAMESPACE >>"; +var eventHubName = "<< NAME OF THE EVENT HUB >>"; + +var producerOptions = new EventHubProducerClientOptions(); +producerOptions.ConnectionOptions.CustomEndpointAddress = new Uri("amqps://app-gateway.mycompany.com"); + +var producer = new EventHubProducerClient( + connectionString, + eventHubName, + producerOptions); +``` + ### Configuring the client retry thresholds The built-in retry policy offers an implementation for an exponential back-off strategy by default, as this provides a good balance between making forward progress and allowing for transient issues that may take some time to resolve. The built-in policy also offers a fixed strategy for those cases where your application requires that you have a deterministic understanding of how long an operation may take. diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/src/Azure.Messaging.EventHubs.csproj b/sdk/eventhub/Azure.Messaging.EventHubs/src/Azure.Messaging.EventHubs.csproj index 4a6a8a562f82..23c6eee36b3c 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs/src/Azure.Messaging.EventHubs.csproj +++ b/sdk/eventhub/Azure.Messaging.EventHubs/src/Azure.Messaging.EventHubs.csproj @@ -1,7 +1,7 @@ Azure Event Hubs is a highly scalable publish-subscribe service that can ingest millions of events per second and stream them to multiple consumers. This client library allows for both publishing and consuming events using Azure Event Hubs. For more information about Event Hubs, see https://azure.microsoft.com/en-us/services/event-hubs/ - 5.3.0-beta.5 + 5.3.0 5.2.0 Azure;Event Hubs;EventHubs;.NET;AMQP;IoT;$(PackageCommonTags) $(RequiredTargetFrameworks) diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/src/Producer/EventDataBatch.cs b/sdk/eventhub/Azure.Messaging.EventHubs/src/Producer/EventDataBatch.cs index e26c81884d5f..5e30aa55d27f 100755 --- a/sdk/eventhub/Azure.Messaging.EventHubs/src/Producer/EventDataBatch.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/src/Producer/EventDataBatch.cs @@ -145,6 +145,12 @@ internal EventDataBatch(TransportEventBatch transportBatch, /// /// true if the event was added; otherwise, false. /// + /// + /// When an event is accepted into the batch, its content and state are frozen; any + /// changes made to the event will not be reflected in the batch nor will any state + /// transitions be reflected to the original instance. + /// + /// /// /// When a batch is published, it will be locked for the duration of that operation. During this time, /// no events may be added to the batch. Calling TryAdd while the batch is being published will diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Snippets/Sample02_EventHubsClientsLiveTests.cs b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Snippets/Sample02_EventHubsClientsLiveTests.cs index f15c1b35ee1e..a661ff04b510 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Snippets/Sample02_EventHubsClientsLiveTests.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Snippets/Sample02_EventHubsClientsLiveTests.cs @@ -30,15 +30,12 @@ public class Sample02_EventHubsClientsLiveTests [Test] public async Task ConfigureProducerTransportWithFullOptions() { - await using var scope = await EventHubScope.CreateAsync(1); - #region Snippet:EventHubs_Sample02_ProducerTransportFullConnectionOptions var connectionString = "<< CONNECTION STRING FOR THE EVENT HUBS NAMESPACE >>"; var eventHubName = "<< NAME OF THE EVENT HUB >>"; /*@@*/ /*@@*/ connectionString = EventHubsTestEnvironment.Instance.EventHubsConnectionString; - /*@@*/ eventHubName = scope.EventHubName; var producerOptions = new EventHubProducerClientOptions { @@ -68,15 +65,12 @@ public async Task ConfigureProducerTransportWithFullOptions() [Test] public async Task ConfigureProducerTransportByProperty() { - await using var scope = await EventHubScope.CreateAsync(1); - #region Snippet:EventHubs_Sample02_ProducerTransportProperty var connectionString = "<< CONNECTION STRING FOR THE EVENT HUBS NAMESPACE >>"; var eventHubName = "<< NAME OF THE EVENT HUB >>"; /*@@*/ /*@@*/ connectionString = EventHubsTestEnvironment.Instance.EventHubsConnectionString; - /*@@*/ eventHubName = scope.EventHubName; var producerOptions = new EventHubProducerClientOptions(); producerOptions.ConnectionOptions.TransportType = EventHubsTransportType.AmqpWebSockets; @@ -101,15 +95,12 @@ public async Task ConfigureProducerTransportByProperty() [Test] public async Task ConfigureProducerProxyWithFullOptions() { - await using var scope = await EventHubScope.CreateAsync(1); - #region Snippet:EventHubs_Sample02_ProducerProxyFullConnectionOptions var connectionString = "<< CONNECTION STRING FOR THE EVENT HUBS NAMESPACE >>"; var eventHubName = "<< NAME OF THE EVENT HUB >>"; /*@@*/ /*@@*/ connectionString = EventHubsTestEnvironment.Instance.EventHubsConnectionString; - /*@@*/ eventHubName = scope.EventHubName; var producerOptions = new EventHubProducerClientOptions { @@ -172,10 +163,38 @@ public async Task ConfigureProducerProxyByProperty() /// /// [Test] - public async Task ConfigureConsumerRetryWithFullOptions() + public async Task ConfigureCustomEndpointAddress() { - await using var scope = await EventHubScope.CreateAsync(1); + #region Snippet:EventHubs_Sample02_ConnectionOptionsCustomEndpoint + + var connectionString = "<< CONNECTION STRING FOR THE EVENT HUBS NAMESPACE >>"; + var eventHubName = "<< NAME OF THE EVENT HUB >>"; + /*@@*/ + /*@@*/ connectionString = EventHubsTestEnvironment.Instance.EventHubsConnectionString; + + var producerOptions = new EventHubProducerClientOptions(); + producerOptions.ConnectionOptions.CustomEndpointAddress = new Uri("amqps://app-gateway.mycompany.com"); + + var producer = new EventHubProducerClient( + connectionString, + eventHubName, + producerOptions); + + #endregion + using var cancellationSource = new CancellationTokenSource(); + cancellationSource.CancelAfter(EventHubsTestEnvironment.Instance.TestExecutionTimeLimit); + + await producer.CloseAsync(cancellationSource.Token).IgnoreExceptions(); + } + + /// + /// Performs basic smoke test validation of the contained snippet. + /// + /// + [Test] + public async Task ConfigureConsumerRetryWithFullOptions() + { #region Snippet:EventHubs_Sample02_ConsumerRetryWithFullOptions var connectionString = "<< CONNECTION STRING FOR THE EVENT HUBS NAMESPACE >>"; @@ -183,7 +202,6 @@ public async Task ConfigureConsumerRetryWithFullOptions() var consumerGroup = EventHubConsumerClient.DefaultConsumerGroupName; /*@@*/ /*@@*/ connectionString = EventHubsTestEnvironment.Instance.EventHubsConnectionString; - /*@@*/ eventHubName = scope.EventHubName; var consumerOptions = new EventHubConsumerClientOptions { @@ -217,8 +235,6 @@ public async Task ConfigureConsumerRetryWithFullOptions() [Test] public async Task ConfigureConsumerRetryByProperty() { - await using var scope = await EventHubScope.CreateAsync(1); - #region Snippet:EventHubs_Sample02_ConsumerRetryByProperty var connectionString = "<< CONNECTION STRING FOR THE EVENT HUBS NAMESPACE >>"; @@ -226,7 +242,6 @@ public async Task ConfigureConsumerRetryByProperty() var consumerGroup = EventHubConsumerClient.DefaultConsumerGroupName; /*@@*/ /*@@*/ connectionString = EventHubsTestEnvironment.Instance.EventHubsConnectionString; - /*@@*/ eventHubName = scope.EventHubName; var consumerOptions = new EventHubConsumerClientOptions(); consumerOptions.RetryOptions.Mode = EventHubsRetryMode.Fixed;