public async Task Start(CancellationToken cancellationToken) { while (!cancellationToken.IsCancellationRequested) { try { var options = new EventHubProducerClientOptions { RetryOptions = new EventHubsRetryOptions { TryTimeout = Configuration.SendTimeout } }; var producer = new EventHubProducerClient(Configuration.EventHubsConnectionString, Configuration.EventHub, options); await using (producer.ConfigureAwait(false)) { while (!cancellationToken.IsCancellationRequested) { // Query partitions each iteration to allow any new partitions to be discovered. Dynamic upscaling of partitions // is a near-term feature being added to the Event Hubs service. var partitions = await producer.GetPartitionIdsAsync(cancellationToken).ConfigureAwait(false); var selectedPartition = partitions[RandomNumberGenerator.Value.Next(0, partitions.Length)]; var batchEvents = new List <EventData>(); // Create the batch and generate a set of random events, keeping only those that were able to fit into the batch. using var batch = await producer.CreateBatchAsync(new CreateBatchOptions { PartitionId = selectedPartition }).ConfigureAwait(false); var events = EventGenerator.CreateEvents( Configuration.PublishBatchSize, Configuration.LargeMessageRandomFactorPercent, Configuration.PublishingBodyMinBytes, Configuration.PublishingBodyRegularMaxBytes, currentSequence, selectedPartition); foreach (var currentEvent in events) { if (!batch.TryAdd(currentEvent)) { break; } batchEvents.Add(currentEvent); } // Publish the events and report them, capturing any failures specific to the send operation. try { if (batch.Count > 0) { await producer.SendAsync(batch, cancellationToken).ConfigureAwait(false); foreach (var batchEvent in batchEvents) { batchEvent.Properties.TryGetValue(EventGenerator.IdPropertyName, out var id); PublishedEvents.AddOrUpdate(id.ToString(), _ => batchEvent, (k, v) => batchEvent); } Interlocked.Add(ref Metrics.EventsPublished, batch.Count); Interlocked.Increment(ref Metrics.TotalServiceOperations); } } catch (TaskCanceledException) { } catch (EventHubsException ex) { Interlocked.Increment(ref Metrics.TotalExceptions); Interlocked.Increment(ref Metrics.SendExceptions); ex.TrackMetrics(Metrics); ErrorsObserved.Add(ex); } catch (Exception ex) { Interlocked.Increment(ref Metrics.TotalExceptions); Interlocked.Increment(ref Metrics.SendExceptions); Interlocked.Increment(ref Metrics.GeneralExceptions); ErrorsObserved.Add(ex); } // Honor any requested delays to throttle publishing so that it doesn't overwhelm slower consumers. if ((Configuration.PublishingDelay.HasValue) && (Configuration.PublishingDelay.Value > TimeSpan.Zero)) { await Task.Delay(Configuration.PublishingDelay.Value).ConfigureAwait(false); } } } } catch (TaskCanceledException) { // No action needed. } catch (Exception ex) when (ex is OutOfMemoryException || ex is StackOverflowException || ex is ThreadAbortException) { throw; } catch (Exception ex) { Interlocked.Increment(ref Metrics.ProducerRestarted); ErrorsObserved.Add(ex); } } }