/// <summary> /// Starts the partition pump. In case it's already running, nothing happens. /// </summary> /// /// <returns>A task to be resolved on when the operation has completed.</returns> /// public async Task StartAsync() { if (RunningTask == null) { await RunningTaskSemaphore.WaitAsync().ConfigureAwait(false); try { if (RunningTask == null) { RunningTaskTokenSource?.Cancel(); RunningTaskTokenSource = new CancellationTokenSource(); InnerConsumer = InnerClient.CreateConsumer(ConsumerGroup, PartitionId, Options.InitialEventPosition); await PartitionProcessor.InitializeAsync().ConfigureAwait(false); RunningTask = RunAsync(RunningTaskTokenSource.Token); } } finally { RunningTaskSemaphore.Release(); } } }
/// <summary> /// Starts the partition pump. In case it's already running, nothing happens. /// </summary> /// /// <returns>A task to be resolved on when the operation has completed.</returns> /// public async Task StartAsync() { if (RunningTask == null) { await RunningTaskSemaphore.WaitAsync().ConfigureAwait(false); try { if (RunningTask == null) { // We expect the token source to be null, but we are playing safe. RunningTaskTokenSource?.Cancel(); RunningTaskTokenSource = new CancellationTokenSource(); InnerConsumer = InnerClient.CreateConsumer(ConsumerGroup, Context.PartitionId, Options.InitialEventPosition); // In case an exception is encountered while partition processor is initializing, don't catch it // and let the event processor handle it. The inner consumer hasn't connected to the service yet, // so there's no need to close it. await PartitionProcessor.InitializeAsync(Context).ConfigureAwait(false); // Before closing, the running task will set the close reason in case of failure. When something // unexpected happens and it's not set, the default value (Unknown) is kept. RunningTask = RunAsync(RunningTaskTokenSource.Token); } } finally { RunningTaskSemaphore.Release(); } } }
/// <summary> /// Creates an Event Hub consumer responsible for reading <see cref="EventData" /> from a specific Event Hub partition, /// and as a member of a specific consumer group. /// /// A consumer may be exclusive, which asserts ownership over the partition for the consumer /// group to ensure that only one consumer from that group is reading the from the partition. /// These exclusive consumers are sometimes referred to as "Epoch Consumers." /// /// A consumer may also be non-exclusive, allowing multiple consumers from the same consumer /// group to be actively reading events from the partition. These non-exclusive consumers are /// sometimes referred to as "Non-epoch Consumers." /// /// Designating a consumer as exclusive may be specified in the <paramref name="consumerOptions" />. /// By default, consumers are created as non-exclusive. /// </summary> /// /// <param name="partitionId">The identifier of the Event Hub partition from which events will be received.</param> /// <param name="eventPosition">The position within the partition where the consumer should begin reading events.</param> /// <param name="consumerOptions">The set of options to apply when creating the consumer.</param> /// /// <returns>An Event Hub consumer configured in the requested manner.</returns> /// public virtual EventHubConsumer CreateConsumer(string partitionId, EventPosition eventPosition, EventHubConsumerOptions consumerOptions = default) { Guard.ArgumentNotNullOrEmpty(nameof(partitionId), partitionId); Guard.ArgumentNotNull(nameof(eventPosition), eventPosition); var options = consumerOptions?.Clone() ?? new EventHubConsumerOptions { Retry = null, DefaultMaximumReceiveWaitTime = null }; options.Retry = options.Retry ?? ClientOptions.Retry.Clone(); options.DefaultMaximumReceiveWaitTime = options.MaximumReceiveWaitTimeOrDefault ?? ClientOptions.DefaultTimeout; return(InnerClient.CreateConsumer(partitionId, eventPosition, options)); }