예제 #1
0
        public async Task BufferedConfiguration()
        {
            await using var scope = await EventHubScope.CreateAsync(1);

            #region Snippet:EventHubs_Sample04_BufferedConfiguration

#if SNIPPET
            var connectionString = "<< CONNECTION STRING FOR THE EVENT HUBS NAMESPACE >>";
            var eventHubName     = "<< NAME OF THE EVENT HUB >>";
#else
            var connectionString = EventHubsTestEnvironment.Instance.EventHubsConnectionString;
            var eventHubName     = scope.EventHubName;
#endif

            var options = new EventHubBufferedProducerClientOptions
            {
                MaximumWaitTime                      = TimeSpan.FromSeconds(1),
                MaximumConcurrentSends               = 5,
                MaximumConcurrentSendsPerPartition   = 1,
                MaximumEventBufferLengthPerPartition = 5000,
                EnableIdempotentRetries              = true
            };

            var producer = new EventHubBufferedProducerClient(connectionString, eventHubName, options);

            // The failure handler is required and invoked after all allowable
            // retries were applied.

            producer.SendEventBatchFailedAsync += args =>
            {
                Debug.WriteLine($"Publishing failed for { args.EventBatch.Count } events.  Error: '{ args.Exception.Message }'");
                return(Task.CompletedTask);
            };

            // The success handler is optional.

            producer.SendEventBatchSucceededAsync += args =>
            {
                Debug.WriteLine($"{ args.EventBatch.Count } events were published to partition: '{ args.PartitionId }.");
                return(Task.CompletedTask);
            };

            try
            {
                for (var index = 0; index < 5; ++index)
                {
                    var eventData = new EventData($"Event #{ index }");
                    await producer.EnqueueEventAsync(eventData);
                }
            }
            finally
            {
                // Closing the producer will flush any
                // enqueued events that have not been published.

                await producer.CloseAsync();
            }

            #endregion
        }
예제 #2
0
        private async Task PerformEnqueue(EventHubBufferedProducerClient producer,
                                          CancellationToken cancellationToken)
        {
            var events = EventGenerator.CreateEvents(_testConfiguration.MaximumEventListSize,
                                                     _testConfiguration.EventEnqueueListSize,
                                                     _testConfiguration.LargeMessageRandomFactorPercent,
                                                     _testConfiguration.PublishingBodyMinBytes,
                                                     _testConfiguration.PublishingBodyRegularMaxBytes);

            try
            {
                await producer.EnqueueEventsAsync(events, cancellationToken).ConfigureAwait(false);

                _metrics.Client.GetMetric(_metrics.EventsEnqueued).TrackValue(_testConfiguration.EventEnqueueListSize);
            }
            catch (TaskCanceledException)
            {
                // Run is completed.
            }
            catch (Exception ex)
            {
                var eventProperties = new Dictionary <String, String>();

                // Track that the exception took place during the enqueuing of an event

                eventProperties.Add("Process", "Enqueue");

                _metrics.Client.TrackException(ex, eventProperties);
            }
        }
        public void CannotUnregisterEventHandlersWhenNotSet()
        {
            var mockProducer     = new Mock <EventHubProducerClient>();
            var bufferedProducer = new EventHubBufferedProducerClient(mockProducer.Object);

            Assert.That(() => bufferedProducer.SendEventBatchSucceededAsync -= args => Task.CompletedTask, Throws.InstanceOf <ArgumentException>(), "The success handler should not allow removing an unset handler.");
            Assert.That(() => bufferedProducer.SendEventBatchFailedAsync    -= args => Task.CompletedTask, Throws.InstanceOf <ArgumentException>(), "The failure handler should not allow removing an unset handler.");
        }
        public void NullEventHandlersAreNotAllowed()
        {
            var mockProducer     = new Mock <EventHubProducerClient>();
            var bufferedProducer = new EventHubBufferedProducerClient(mockProducer.Object);

            Assert.That(() => bufferedProducer.SendEventBatchSucceededAsync += null, Throws.InstanceOf <ArgumentNullException>(), "The success handler should not allow null.");
            Assert.That(() => bufferedProducer.SendEventBatchFailedAsync    += null, Throws.InstanceOf <ArgumentNullException>(), "The failure handler should not allow null.");
        }
        public async Task PartitionIdBuffered()
        {
            await using var scope = await EventHubScope.CreateAsync(1);

            #region Snippet:EventHubs_Sample04_PartitionIdBuffered

#if SNIPPET
            var connectionString = "<< CONNECTION STRING FOR THE EVENT HUBS NAMESPACE >>";
            var eventHubName     = "<< NAME OF THE EVENT HUB >>";
#else
            var connectionString = EventHubsTestEnvironment.Instance.EventHubsConnectionString;
            var eventHubName     = scope.EventHubName;
#endif

            var producer = new EventHubBufferedProducerClient(connectionString, eventHubName);

            // The failure handler is required and invoked after all allowable
            // retries were applied.

            producer.SendEventBatchFailedAsync += args =>
            {
                Debug.WriteLine($"Publishing failed for { args.EventBatch.Count } events.  Error: '{ args.Exception.Message }'");
                return(Task.CompletedTask);
            };

            // The success handler is optional.

            producer.SendEventBatchSucceededAsync += args =>
            {
                Debug.WriteLine($"{ args.EventBatch.Count } events were published to partition: '{ args.PartitionId }.");
                return(Task.CompletedTask);
            };

            try
            {
                string firstPartition = (await producer.GetPartitionIdsAsync()).First();

                var enqueueOptions = new EnqueueEventOptions
                {
                    PartitionId = firstPartition
                };

                for (var index = 0; index < 5; ++index)
                {
                    var eventData = new EventData($"Event #{ index }");
                    await producer.EnqueueEventAsync(eventData, enqueueOptions);
                }
            }
            finally
            {
                // Closing the producer will flush any
                // enqueued events that have not been published.

                await producer.CloseAsync();
            }

            #endregion
        }
        /// <summary>
        ///   Performs the tasks needed to initialize and set up the environment for the test scenario.
        ///   This setup will take place once for each instance, running after the global setup has
        ///   completed.
        /// </summary>
        ///
        public override async Task SetupAsync()
        {
            await base.SetupAsync();

            Scope = await EventHubScope.CreateAsync(Options.PartitionCount).ConfigureAwait(false);

            var producerOptions = new EventHubBufferedProducerClientOptions
            {
                MaximumWaitTime = (Options.MaximumWaitTimeMilliseconds.HasValue) ? TimeSpan.FromMilliseconds(Options.MaximumWaitTimeMilliseconds.Value) : null,
                MaximumEventBufferLengthPerPartition = Options.MaximumBufferLength,
                MaximumConcurrentSendsPerPartition   = Options.MaximumConcurrentSendsPerPartition
            };

            if (Options.MaximumConcurrentSends.HasValue)
            {
                producerOptions.MaximumConcurrentSends = Options.MaximumConcurrentSends.Value;
            }

            _producer = new EventHubBufferedProducerClient(TestEnvironment.EventHubsConnectionString, Scope.EventHubName, producerOptions);

            // Create the handlers that call into the performance test infrastructure to
            // report when errors and events are observed.

            _producer.SendEventBatchFailedAsync += args =>
            {
                // Do not flag cancellation as a failure; it is expected for in-flight batches when
                // the test run is cleaning up.

                if (!typeof(OperationCanceledException).IsAssignableFrom(args.Exception.GetType()))
                {
                    ErrorRaised(args.Exception);
                }

                return(Task.CompletedTask);
            };

            _producer.SendEventBatchSucceededAsync += args =>
            {
                for (var index = 0; index < args.EventBatch.Count; ++index)
                {
                    EventRaised();
                }

                return(Task.CompletedTask);
            };

            // Read the available partitions and buffer a single events to establish the
            // connection and link and start reading the buffers.

            Partitions = await _producer.GetPartitionIdsAsync().ConfigureAwait(false);

            await _producer.EnqueueEventsAsync(EventGenerator.CreateEvents(1)).ConfigureAwait(false);

            // Start the background publishing task.

            _backgroundCancellationSource = new CancellationTokenSource();
            _backgroundBufferingTask      = EnqueueEvents(_backgroundCancellationSource.Token);
        }
        public void OnlyOneEventHandlerIsAllowed()
        {
            var mockProducer     = new Mock <EventHubProducerClient>();
            var bufferedProducer = new EventHubBufferedProducerClient(mockProducer.Object);

            bufferedProducer.SendEventBatchSucceededAsync += args => Task.CompletedTask;
            bufferedProducer.SendEventBatchFailedAsync    += args => Task.CompletedTask;

            Assert.That(() => bufferedProducer.SendEventBatchSucceededAsync += args => Task.CompletedTask, Throws.InstanceOf <NotSupportedException>(), "The success handler should only allow one handler registration.");
            Assert.That(() => bufferedProducer.SendEventBatchFailedAsync    += args => Task.CompletedTask, Throws.InstanceOf <NotSupportedException>(), "The failure handler should only allow one handler registration.");
        }
        public async Task GetEventHubPropertiesAsyncIsDelegated()
        {
            using var cancellationSource = new CancellationTokenSource();

            var mockProducer     = new Mock <EventHubProducerClient>();
            var bufferedProducer = new EventHubBufferedProducerClient(mockProducer.Object);

            await bufferedProducer.GetEventHubPropertiesAsync(cancellationSource.Token);

            mockProducer.Verify(producer => producer.GetEventHubPropertiesAsync(cancellationSource.Token), Times.Once);
        }
        public async Task CloseAsyncClosesTheProducer()
        {
            using var cancellationSource = new CancellationTokenSource();

            var mockProducer = new Mock <EventHubProducerClient>("fakeNS", "fakeHub", Mock.Of <TokenCredential>(), new EventHubProducerClientOptions {
                Identifier = "abc123"
            });
            var bufferedProducer = new EventHubBufferedProducerClient(mockProducer.Object);

            await bufferedProducer.CloseAsync(false, cancellationSource.Token);

            mockProducer.Verify(producer => producer.CloseAsync(CancellationToken.None), Times.Once);
        }
        public void RegisteredEventHandlersCanBeUnregistered()
        {
            var mockProducer     = new Mock <EventHubProducerClient>();
            var bufferedProducer = new EventHubBufferedProducerClient(mockProducer.Object);

            Func <SendEventBatchSucceededEventArgs, Task> successHandler = args => Task.CompletedTask;
            Func <SendEventBatchFailedEventArgs, Task>    failHandler    = args => Task.CompletedTask;

            bufferedProducer.SendEventBatchSucceededAsync += successHandler;
            bufferedProducer.SendEventBatchFailedAsync    += failHandler;

            Assert.That(() => bufferedProducer.SendEventBatchSucceededAsync -= successHandler, Throws.Nothing, "The success handler should allow removing the registered delegate.");
            Assert.That(() => bufferedProducer.SendEventBatchFailedAsync    -= failHandler, Throws.Nothing, "The failure handler should allow removing the registered delegate.");
        }
        public async Task GetPartitionIdsAsyncIsDelegated()
        {
            using var cancellationSource = new CancellationTokenSource();

            var mockProducer     = new Mock <EventHubProducerClient>();
            var bufferedProducer = new EventHubBufferedProducerClient(mockProducer.Object);

            mockProducer
            .Setup(producer => producer.GetPartitionIdsAsync(It.IsAny <CancellationToken>()))
            .ReturnsAsync(new[] { "0 " });

            await bufferedProducer.GetPartitionIdsAsync(cancellationSource.Token);

            mockProducer.Verify(producer => producer.GetPartitionIdsAsync(cancellationSource.Token), Times.Once);
        }
        public void ConnectionConstructorSetsDelegatedProperties()
        {
            var expectedIdentifier = "Test-Identifier";
            var expectedNamespace  = "testns.namespace.com";
            var expectedEventHub   = "testHub";
            var options            = new EventHubBufferedProducerClientOptions {
                Identifier = expectedIdentifier
            };
            var connection = new EventHubConnection(expectedNamespace, expectedEventHub, Mock.Of <TokenCredential>());
            var producer   = new EventHubBufferedProducerClient(connection, options);

            Assert.That(producer.Identifier, Is.EqualTo(expectedIdentifier), "The identifier should have been initialized.");
            Assert.That(producer.FullyQualifiedNamespace, Is.EqualTo(expectedNamespace), "The fully qualified namespace should have been initialized.");
            Assert.That(producer.EventHubName, Is.EqualTo(expectedEventHub), "The event hub name should have been initialized.");
        }
        public void SasCredentialConstructorSetsDelegatedProperties()
        {
            var expectedIdentifier = "Test-Identifier";
            var expectedNamespace  = "testns.namespace.com";
            var expectedEventHub   = "testHub";
            var credential         = new AzureSasCredential(new SharedAccessSignature("sb://this.is.Fake/blah", "key", "value").Value);
            var options            = new EventHubBufferedProducerClientOptions {
                Identifier = expectedIdentifier
            };
            var producer = new EventHubBufferedProducerClient(expectedNamespace, expectedEventHub, credential, options);

            Assert.That(producer.Identifier, Is.EqualTo(expectedIdentifier), "The identifier should have been initialized.");
            Assert.That(producer.FullyQualifiedNamespace, Is.EqualTo(expectedNamespace), "The fully qualified namespace should have been initialized.");
            Assert.That(producer.EventHubName, Is.EqualTo(expectedEventHub), "The event hub name should have been initialized.");
        }
        public void ConnectionStringAndEventHubConstructorSetsDelegatedProperties()
        {
            var expectedIdentifier = "Test-Identifier";
            var expectedNamespace  = "testns.namespace.com";
            var expectedEventHub   = "testHub";
            var connectionString   = $"Endpoint=sb://{ expectedNamespace };SharedAccessKeyName=ABC;SharedAccessKey=123";
            var options            = new EventHubBufferedProducerClientOptions {
                Identifier = expectedIdentifier
            };
            var producer = new EventHubBufferedProducerClient(connectionString, expectedEventHub, options);

            Assert.That(producer.Identifier, Is.EqualTo(expectedIdentifier), "The identifier should have been initialized.");
            Assert.That(producer.FullyQualifiedNamespace, Is.EqualTo(expectedNamespace), "The fully qualified namespace should have been initialized.");
            Assert.That(producer.EventHubName, Is.EqualTo(expectedEventHub), "The event hub name should have been initialized.");
        }
        public void CannotUnRegisterHandlersWhenPublishingIsActive()
        {
            var mockProducer     = new Mock <EventHubProducerClient>();
            var bufferedProducer = new EventHubBufferedProducerClient(mockProducer.Object);

            Func <SendEventBatchSucceededEventArgs, Task> successHandler = args => Task.CompletedTask;
            Func <SendEventBatchFailedEventArgs, Task>    failHandler    = args => Task.CompletedTask;

            bufferedProducer.SendEventBatchSucceededAsync += successHandler;
            bufferedProducer.SendEventBatchFailedAsync    += failHandler;

            bufferedProducer.IsPublishing = true;

            Assert.That(() => bufferedProducer.SendEventBatchSucceededAsync -= successHandler, Throws.InstanceOf <NotSupportedException>(), "The success handler should not allow unregistering when publishing is active.");
            Assert.That(() => bufferedProducer.SendEventBatchFailedAsync    -= failHandler, Throws.InstanceOf <NotSupportedException>(), "The failure handler should not allow unregistering when publishing is active.");
        }
        public async Task GetPartitionPropertiesAsyncIsDelegated()
        {
            using var cancellationSource = new CancellationTokenSource();

            var expectedPartition = "0";
            var mockProducer      = new Mock <EventHubProducerClient>();
            var bufferedProducer  = new EventHubBufferedProducerClient(mockProducer.Object);

            mockProducer
            .Setup(producer => producer.GetPartitionPropertiesAsync(
                       It.IsAny <string>(),
                       It.IsAny <CancellationToken>()))
            .ReturnsAsync(new PartitionProperties("test", "1", true, 12345, 6789, 22, new DateTimeOffset(2015, 10, 27, 0, 0, 0, TimeSpan.Zero)));

            await bufferedProducer.GetPartitionPropertiesAsync(expectedPartition, cancellationSource.Token);

            mockProducer.Verify(producer => producer.GetPartitionPropertiesAsync(expectedPartition, cancellationSource.Token), Times.Once);
        }
        public async Task CloseAsyncUnregistersTheEventHandlers()
        {
            using var cancellationSource = new CancellationTokenSource();

            var mockProducer = new Mock <EventHubProducerClient>("fakeNS", "fakeHub", Mock.Of <TokenCredential>(), new EventHubProducerClientOptions {
                Identifier = "abc123"
            });
            var bufferedProducer = new EventHubBufferedProducerClient(mockProducer.Object);

            Func <SendEventBatchSucceededEventArgs, Task> successHandler = args => Task.CompletedTask;
            Func <SendEventBatchFailedEventArgs, Task>    failHandler    = args => Task.CompletedTask;

            bufferedProducer.SendEventBatchSucceededAsync += successHandler;
            bufferedProducer.SendEventBatchFailedAsync    += failHandler;

            await bufferedProducer.CloseAsync(false, cancellationSource.Token);

            // The handlers should have been unregistered; attempting to do so again should cause
            // an exception.

            Assert.That(() => bufferedProducer.SendEventBatchSucceededAsync -= successHandler, Throws.InstanceOf <ArgumentException>(), "The success handler should have already been unregistered.");
            Assert.That(() => bufferedProducer.SendEventBatchFailedAsync    -= failHandler, Throws.InstanceOf <ArgumentException>(), "The failure handler should have already been unregistered.");
        }
        public async Task CustomMetadata()
        {
            await using var scope = await EventHubScope.CreateAsync(1);

            #region Snippet:EventHubs_Sample04_CustomMetadata

#if SNIPPET
            var connectionString = "<< CONNECTION STRING FOR THE EVENT HUBS NAMESPACE >>";
            var eventHubName     = "<< NAME OF THE EVENT HUB >>";
#else
            var connectionString = EventHubsTestEnvironment.Instance.EventHubsConnectionString;
            var eventHubName     = scope.EventHubName;
#endif

            var producer = new EventHubBufferedProducerClient(connectionString, eventHubName);

            // The failure handler is required and invoked after all allowable
            // retries were applied.

            producer.SendEventBatchFailedAsync += args =>
            {
                Debug.WriteLine($"Publishing failed for { args.EventBatch.Count } events.  Error: '{ args.Exception.Message }'");
                return(Task.CompletedTask);
            };

            // The success handler is optional.

            producer.SendEventBatchSucceededAsync += args =>
            {
                Debug.WriteLine($"{ args.EventBatch.Count } events were published to partition: '{ args.PartitionId }.");
                return(Task.CompletedTask);
            };

            try
            {
                var eventData = new EventData("Hello, Event Hubs!")
                {
                    MessageId   = "H1",
                    ContentType = "application/json"
                };

                eventData.Properties.Add("EventType", "com.microsoft.samples.hello-event");
                eventData.Properties.Add("priority", 1);
                eventData.Properties.Add("score", 9.0);

                await producer.EnqueueEventAsync(eventData);

                eventData = new EventData("Goodbye, Event Hubs!")
                {
                    MessageId   = "G1",
                    ContentType = "application/json"
                };

                eventData.Properties.Add("EventType", "com.microsoft.samples.goodbye-event");
                eventData.Properties.Add("priority", "17");
                eventData.Properties.Add("blob", true);

                await producer.EnqueueEventAsync(eventData);
            }
            finally
            {
                // Closing the producer will flush any
                // enqueued events that have not been published.

                await producer.CloseAsync();
            }

            #endregion
        }
예제 #19
0
        public async Task Start(CancellationToken cancellationToken)
        {
            var enqueueTasks = new List <Task>();

            while (!cancellationToken.IsCancellationRequested)
            {
                using var backgroundCancellationSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);

                // Create the buffered producer client and register the success and failure handlers

                var options = new EventHubBufferedProducerClientOptions
                {
                    RetryOptions = new EventHubsRetryOptions
                    {
                        TryTimeout     = _testConfiguration.SendTimeout,
                        MaximumRetries = 15
                    },
                    MaximumWaitTime = _testConfiguration.MaxWaitTime
                };
                var producer = new EventHubBufferedProducerClient(_connectionString, _eventHubName, options);

                try
                {
                    producer.SendEventBatchSucceededAsync += args =>
                    {
                        var numEvents = args.EventBatch.Count;

                        _metrics.Client.GetMetric(_metrics.SuccessfullySentFromQueue, "PartitionId").TrackValue(numEvents, args.PartitionId);
                        _metrics.Client.GetMetric(_metrics.BatchesPublished).TrackValue(1);

                        return(Task.CompletedTask);
                    };

                    producer.SendEventBatchFailedAsync += args =>
                    {
                        var numEvents = args.EventBatch.Count;

                        _metrics.Client.GetMetric(_metrics.EventsNotSentAfterEnqueue, "PartitionId").TrackValue(numEvents, args.PartitionId);
                        _metrics.Client.TrackException(args.Exception);

                        return(Task.CompletedTask);
                    };

                    // Start concurrent enqueuing tasks

                    if (_testConfiguration.ConcurrentSends > 1)
                    {
                        for (var index = 0; index < _testConfiguration.ConcurrentSends - 1; ++index)
                        {
                            enqueueTasks.Add(Task.Run(async() =>
                            {
                                while (!cancellationToken.IsCancellationRequested)
                                {
                                    await PerformEnqueue(producer, cancellationToken).ConfigureAwait(false);

                                    if ((_testConfiguration.ProducerPublishingDelay.HasValue) && (_testConfiguration.ProducerPublishingDelay.Value > TimeSpan.Zero))
                                    {
                                        await Task.Delay(_testConfiguration.ProducerPublishingDelay.Value, backgroundCancellationSource.Token).ConfigureAwait(false);
                                    }
                                }
                            }));
                        }
                    }
                    // Perform one of the sends in the foreground, which will allow easier detection of a
                    // processor-level issue.

                    while (!cancellationToken.IsCancellationRequested)
                    {
                        try
                        {
                            await PerformEnqueue(producer, cancellationToken).ConfigureAwait(false);

                            if ((_testConfiguration.ProducerPublishingDelay.HasValue) && (_testConfiguration.ProducerPublishingDelay.Value > TimeSpan.Zero))
                            {
                                await Task.Delay(_testConfiguration.ProducerPublishingDelay.Value, cancellationToken).ConfigureAwait(false);
                            }
                        }
                        catch (TaskCanceledException)
                        {
                            backgroundCancellationSource.Cancel();
                            await Task.WhenAll(enqueueTasks).ConfigureAwait(false);
                        }
                    }
                }
                catch (TaskCanceledException)
                {
                    // No action needed, the cancellation token has been cancelled.
                }
                catch (Exception ex) when
                    (ex is OutOfMemoryException ||
                    ex is StackOverflowException ||
                    ex is ThreadAbortException)
                {
                    throw;
                }
                catch (Exception ex)
                {
                    // If this catch is hit, it means the producer has restarted, collect metrics.

                    _metrics.Client.GetMetric(_metrics.ProducerRestarted).TrackValue(1);
                    _metrics.Client.TrackException(ex);
                }
                finally
                {
                    await producer.CloseAsync(false);
                }
            }
        }