/// <summary> /// Initializes a new instance of the <see cref="PartitionContext"/> class. /// </summary> /// /// <param name="eventHubName">The name of the Event Hub that this context is associated with.</param> /// <param name="partitionId">The identifier of the Event Hub partition this context is associated with.</param> /// <param name="consumer">The <see cref="TransportConsumer" /> for this context to use as the source for information.</param> /// /// <remarks> /// The <paramref name="consumer" />, if provided, will be held in a weak reference to ensure that it /// does not impact resource use should the partition context be held beyond the lifespan of the /// consumer instance. /// </remarks> /// internal PartitionContext(string eventHubName, string partitionId, TransportConsumer consumer) : this(eventHubName, partitionId) { Argument.AssertNotNull(consumer, nameof(consumer)); SourceConsumer = new WeakReference <TransportConsumer>(consumer); }
/// <summary> /// Initializes a new instance of the <see cref="EventHubConsumerClient"/> class. /// </summary> /// /// <param name="consumerGroup">The name of the consumer group this consumer is associated with. Events are read in the context of this group.</param> /// <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="fullyQualifiedNamespace">The fully qualified Event Hubs namespace to connect to. This is likely to be similar to <c>{yournamespace}.servicebus.windows.net</c>.</param> /// <param name="eventHubName">The name of the specific Event Hub to associate the consumer with.</param> /// <param name="credential">The Azure managed identity credential to use for authorization. Access controls may be specified by the Event Hubs namespace or the requested Event Hub, depending on Azure configuration.</param> /// <param name="consumerOptions">A set of options to apply when configuring the consumer.</param> /// public EventHubConsumerClient(string consumerGroup, string partitionId, EventPosition eventPosition, string fullyQualifiedNamespace, string eventHubName, TokenCredential credential, EventHubConsumerClientOptions consumerOptions = default) { Argument.AssertNotNullOrEmpty(consumerGroup, nameof(consumerGroup)); Argument.AssertNotNullOrEmpty(partitionId, nameof(partitionId)); Argument.AssertNotNull(eventPosition, nameof(eventPosition)); Argument.AssertNotNullOrEmpty(fullyQualifiedNamespace, nameof(fullyQualifiedNamespace)); Argument.AssertNotNullOrEmpty(eventHubName, nameof(eventHubName)); Argument.AssertNotNull(credential, nameof(credential)); consumerOptions = consumerOptions?.Clone() ?? new EventHubConsumerClientOptions(); OwnsConnection = true; Connection = new EventHubConnection(fullyQualifiedNamespace, eventHubName, credential, consumerOptions.ConnectionOptions); ConsumerGroup = consumerGroup; Options = consumerOptions; RetryPolicy = consumerOptions.RetryOptions.ToRetryPolicy(); InnerConsumer = Connection.CreateTransportConsumer(consumerGroup, partitionId, eventPosition, consumerOptions); PartitionId = partitionId; StartingPosition = eventPosition; }
/// <summary> /// Initializes a new instance of the <see cref="PartitionReceiver"/> class. /// </summary> /// /// <param name="consumerGroup">The name of the consumer group this client is associated with. Events are read in the context of this group.</param> /// <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 client should begin reading events.</param> /// <param name="fullyQualifiedNamespace">The fully qualified Event Hubs namespace to connect to. This is likely to be similar to <c>{yournamespace}.servicebus.windows.net</c>.</param> /// <param name="eventHubName">The name of the specific Event Hub to associate the client with.</param> /// <param name="credential">The Azure managed identity credential to use for authorization. Access controls may be specified by the Event Hubs namespace or the requested Event Hub, depending on Azure configuration.</param> /// <param name="options">A set of options to apply when configuring the client.</param> /// public PartitionReceiver(string consumerGroup, string partitionId, EventPosition eventPosition, string fullyQualifiedNamespace, string eventHubName, TokenCredential credential, PartitionReceiverOptions options = default) { Argument.AssertNotNullOrEmpty(consumerGroup, nameof(consumerGroup)); Argument.AssertNotNullOrEmpty(partitionId, nameof(partitionId)); Argument.AssertWellFormedEventHubsNamespace(fullyQualifiedNamespace, nameof(fullyQualifiedNamespace)); Argument.AssertNotNullOrEmpty(eventHubName, nameof(eventHubName)); Argument.AssertNotNull(credential, nameof(credential)); options = options?.Clone() ?? new PartitionReceiverOptions(); Connection = new EventHubConnection(fullyQualifiedNamespace, eventHubName, credential, options.ConnectionOptions); ConsumerGroup = consumerGroup; PartitionId = partitionId; InitialPosition = eventPosition; DefaultMaximumWaitTime = options.DefaultMaximumReceiveWaitTime; RetryPolicy = options.RetryOptions.ToRetryPolicy(); #pragma warning disable CA2214 // Do not call overridable methods in constructors. This internal method is virtual for testing purposes. InnerConsumer = CreateTransportConsumer(consumerGroup, partitionId, eventPosition, RetryPolicy, options); #pragma warning restore CA2214 // Do not call overridable methods in constructors. }
internal ServiceBusSession( TransportConsumer consumer, ServiceBusRetryPolicy retryPolicy) { _consumer = consumer; _retryPolicy = retryPolicy; }
internal ServiceBusSession( TransportConsumer consumer, string sessionId) { _consumer = consumer; UserSpecifiedSessionId = sessionId; }
/// <summary> /// Initializes a new instance of the <see cref="PartitionContext"/> class. /// </summary> /// /// <param name="fullyQualifiedNamespace">The fully qualified Event Hubs namespace this context is associated with.</param> /// <param name="eventHubName">The name of the Event Hub partition this context is associated with.</param> /// <param name="consumerGroup">The name of the consumer group this context is associated with.</param> /// <param name="partitionId">The identifier of the Event Hub partition this context is associated with.</param> /// <param name="consumer">The <see cref="TransportConsumer" /> for this context to use as the source for information.</param> /// /// <remarks> /// The <paramref name="consumer" />, if provided, will be held in a weak reference to ensure that it /// does not impact resource use should the partition context be held beyond the lifespan of the /// consumer instance. /// </remarks> /// internal PartitionContext(string fullyQualifiedNamespace, string eventHubName, string consumerGroup, string partitionId, TransportConsumer consumer) : this(fullyQualifiedNamespace, eventHubName, consumerGroup, partitionId) { Argument.AssertNotNull(consumer, nameof(consumer)); SourceConsumer = new WeakReference <TransportConsumer>(consumer); }
/// <summary> /// Initializes a new instance of the <see cref="PartitionReceiver"/> class. /// </summary> /// /// <param name="consumerGroup">The name of the consumer group this receiver is associated with. Events are read in the context of this group.</param> /// <param name="partitionId">The identifier of the Event Hub partition from which events will be received.</param> /// <param name="eventHubName">The name of the specific Event Hub to associate the receiver with.</param> /// <param name="trackingLastEnqueuedEvent">A flag indicating whether or not the <paramref name="transportConsumer" /> is tracking last enqueued event information.</param> /// <param name="defaultMaximumReceiveWaitTime">The default amount of time to wait for the requested amount of messages when receiving.</param> /// <param name="transportConsumer">The transport consumer that is used for operations performed against the Event Hubs service.</param> /// internal PartitionReceiver(string consumerGroup, string partitionId, string eventHubName, bool trackingLastEnqueuedEvent, TimeSpan defaultMaximumReceiveWaitTime, TransportConsumer transportConsumer) : this(consumerGroup, partitionId, eventHubName) { Argument.AssertNotNull(transportConsumer, nameof(transportConsumer)); TrackingLastEnqueuedEvent = trackingLastEnqueuedEvent; DefaultMaximumReceiveWaitTime = defaultMaximumReceiveWaitTime; InnerConsumer = transportConsumer; }
/// <summary> /// Initializes a new instance of the <see cref="ServiceBusReceiverClient"/> class. /// </summary> /// /// <param name="connection">The <see cref="ServiceBusConnection" /> connection to use for communication with the Service Bus service.</param> /// <param name="sessionId"></param> /// <param name="clientOptions">A set of options to apply when configuring the consumer.</param> /// internal ServiceBusReceiverClient( ServiceBusConnection connection, string sessionId, ServiceBusReceiverClientOptions clientOptions) { Argument.AssertNotNull(connection, nameof(connection)); Argument.AssertNotNull(clientOptions, nameof(clientOptions)); OwnsConnection = false; Connection = connection; RetryPolicy = clientOptions.RetryOptions.ToRetryPolicy(); ReceiveMode = clientOptions.ReceiveMode; Consumer = Connection.CreateTransportConsumer(retryPolicy: RetryPolicy, sessionId: sessionId); }
/// <summary> /// Initializes a new instance of the <see cref="ServiceBusReceiverClient"/> class. /// </summary> /// /// <param name="connectionString">The connection string to use for connecting to the Service Bus namespace; it is expected that the shared key properties are contained in this connection string, but not the Service Bus entity name.</param> /// <param name="entityName">The name of the specific Service Bus entity to associate the consumer with.</param> /// <param name="clientOptions">A set of options to apply when configuring the consumer.</param> /// <param name="sessionId"></param> /// /// <remarks> /// If the connection string is copied from the Service Bus entity itself, it will contain the name of the desired Service Bus entity, /// and can be used directly without passing the <paramref name="entityName" />. The name of the Service Bus entity should be /// passed only once, either as part of the connection string or separately. /// </remarks> /// internal ServiceBusReceiverClient( string connectionString, string entityName, string sessionId, ServiceBusReceiverClientOptions clientOptions) { Argument.AssertNotNullOrEmpty(connectionString, nameof(connectionString)); Argument.AssertNotNull(clientOptions, nameof(clientOptions)); OwnsConnection = true; Connection = new ServiceBusConnection(connectionString, entityName, clientOptions.ConnectionOptions); RetryPolicy = clientOptions.RetryOptions.ToRetryPolicy(); ReceiveMode = clientOptions.ReceiveMode; Consumer = Connection.CreateTransportConsumer(retryPolicy: RetryPolicy, sessionId: sessionId); }
/// <summary> /// Initializes a new instance of the <see cref="ServiceBusReceiverClient"/> class. /// </summary> /// /// <param name="fullyQualifiedNamespace">The fully qualified Service Bus namespace to connect to. This is likely to be similar to <c>{yournamespace}.servicebus.windows.net</c>.</param> /// <param name="entityName">The name of the specific Service Bus entity to associate the consumer with.</param> /// <param name="credential">The Azure managed identity credential to use for authorization. Access controls may be specified by the Service Bus namespace or the requested Service Bus entity, depending on Azure configuration.</param> /// <param name="sessionId"></param> /// <param name="clientOptions">A set of options to apply when configuring the consumer.</param> /// internal ServiceBusReceiverClient( string fullyQualifiedNamespace, string entityName, TokenCredential credential, string sessionId, ServiceBusReceiverClientOptions clientOptions) { Argument.AssertNotNullOrEmpty(fullyQualifiedNamespace, nameof(fullyQualifiedNamespace)); Argument.AssertNotNullOrEmpty(entityName, nameof(entityName)); Argument.AssertNotNull(credential, nameof(credential)); Argument.AssertNotNull(clientOptions, nameof(clientOptions)); OwnsConnection = true; Connection = new ServiceBusConnection(fullyQualifiedNamespace, entityName, credential, clientOptions.ConnectionOptions); RetryPolicy = clientOptions.RetryOptions.ToRetryPolicy(); ReceiveMode = clientOptions.ReceiveMode; Consumer = Connection.CreateTransportConsumer(retryPolicy: RetryPolicy, sessionId: sessionId); }
/// <summary> /// Initializes a new instance of the <see cref="PartitionReceiver"/> class. /// </summary> /// /// <param name="consumerGroup">The name of the consumer group this client is associated with. Events are read in the context of this group.</param> /// <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 client should begin reading events.</param> /// <param name="connection">The <see cref="EventHubConnection" /> connection to use for communication with the Event Hubs service.</param> /// <param name="options">A set of options to apply when configuring the client.</param> /// public PartitionReceiver(string consumerGroup, string partitionId, EventPosition eventPosition, EventHubConnection connection, PartitionReceiverOptions options = default) { Argument.AssertNotNullOrEmpty(consumerGroup, nameof(consumerGroup)); Argument.AssertNotNullOrEmpty(partitionId, nameof(partitionId)); Argument.AssertNotNull(connection, nameof(connection)); options = options?.Clone() ?? new PartitionReceiverOptions(); OwnsConnection = false; Connection = connection; ConsumerGroup = consumerGroup; PartitionId = partitionId; InitialPosition = eventPosition; RetryPolicy = options.RetryOptions.ToRetryPolicy(); InnerConsumer = CreateTransportConsumer(consumerGroup, partitionId, eventPosition, RetryPolicy, options); }
/// <summary> /// Initializes a new instance of the <see cref="PartitionReceiver"/> class. /// </summary> /// /// <param name="consumerGroup">The name of the consumer group this client is associated with. Events are read in the context of this group.</param> /// <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 client should begin reading events.</param> /// <param name="connectionString">The connection string to use for connecting to the Event Hubs namespace; it is expected that the shared key properties are contained in this connection string, but not the Event Hub name.</param> /// <param name="eventHubName">The name of the specific Event Hub to associate the client with.</param> /// <param name="options">A set of options to apply when configuring the client.</param> /// /// <remarks> /// If the connection string is copied from the Event Hub itself, it will contain the name of the desired Event Hub, /// and can be used directly without passing the <paramref name="eventHubName" />. The name of the Event Hub should be /// passed only once, either as part of the connection string or separately. /// </remarks> /// /// <seealso href="https://docs.microsoft.com/en-us/azure/event-hubs/event-hubs-get-connection-string"/> /// public PartitionReceiver(string consumerGroup, string partitionId, EventPosition eventPosition, string connectionString, string eventHubName, PartitionReceiverOptions options = default) { Argument.AssertNotNullOrEmpty(consumerGroup, nameof(consumerGroup)); Argument.AssertNotNullOrEmpty(partitionId, nameof(partitionId)); Argument.AssertNotNullOrEmpty(connectionString, nameof(connectionString)); options = options?.Clone() ?? new PartitionReceiverOptions(); Connection = new EventHubConnection(connectionString, eventHubName, options.ConnectionOptions); ConsumerGroup = consumerGroup; PartitionId = partitionId; InitialPosition = eventPosition; DefaultMaximumWaitTime = options.DefaultMaximumReceiveWaitTime; RetryPolicy = options.RetryOptions.ToRetryPolicy(); InnerConsumer = CreateTransportConsumer(consumerGroup, partitionId, eventPosition, RetryPolicy, options); }
/// <summary> /// Initializes a new instance of the <see cref="EventHubConsumerClient"/> class. /// </summary> /// /// <param name="consumerGroup">The name of the consumer group this consumer is associated with. Events are read in the context of this group.</param> /// <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="connection">The <see cref="EventHubConnection" /> connection to use for communication with the Event Hubs service.</param> /// <param name="consumerOptions">A set of options to apply when configuring the consumer.</param> /// public EventHubConsumerClient(string consumerGroup, string partitionId, EventPosition eventPosition, EventHubConnection connection, EventHubConsumerClientOptions consumerOptions = default) { Argument.AssertNotNullOrEmpty(consumerGroup, nameof(consumerGroup)); Argument.AssertNotNullOrEmpty(partitionId, nameof(partitionId)); Argument.AssertNotNull(eventPosition, nameof(eventPosition)); Argument.AssertNotNull(connection, nameof(connection)); consumerOptions = consumerOptions?.Clone() ?? new EventHubConsumerClientOptions(); OwnsConnection = false; Connection = connection; ConsumerGroup = consumerGroup; Options = consumerOptions; RetryPolicy = consumerOptions.RetryOptions.ToRetryPolicy(); InnerConsumer = Connection.CreateTransportConsumer(consumerGroup, partitionId, eventPosition, consumerOptions); PartitionId = partitionId; StartingPosition = eventPosition; }
/// <summary> /// Initializes a new instance of the <see cref="PartitionReceiver"/> class. /// </summary> /// /// <param name="consumerGroup">The name of the consumer group this client is associated with. Events are read in the context of this group.</param> /// <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 client should begin reading events.</param> /// <param name="fullyQualifiedNamespace">The fully qualified Event Hubs namespace to connect to. This is likely to be similar to <c>{yournamespace}.servicebus.windows.net</c>.</param> /// <param name="eventHubName">The name of the specific Event Hub to associate the client with.</param> /// <param name="credential">The Azure managed identity credential to use for authorization. Access controls may be specified by the Event Hubs namespace or the requested Event Hub, depending on Azure configuration.</param> /// <param name="options">A set of options to apply when configuring the client.</param> /// public PartitionReceiver(string consumerGroup, string partitionId, EventPosition eventPosition, string fullyQualifiedNamespace, string eventHubName, TokenCredential credential, PartitionReceiverOptions options = default) { Argument.AssertNotNullOrEmpty(consumerGroup, nameof(consumerGroup)); Argument.AssertNotNullOrEmpty(partitionId, nameof(partitionId)); Argument.AssertWellFormedEventHubsNamespace(fullyQualifiedNamespace, nameof(fullyQualifiedNamespace)); Argument.AssertNotNullOrEmpty(eventHubName, nameof(eventHubName)); Argument.AssertNotNull(credential, nameof(credential)); options = options?.Clone() ?? new PartitionReceiverOptions(); Connection = new EventHubConnection(fullyQualifiedNamespace, eventHubName, credential, options.ConnectionOptions); ConsumerGroup = consumerGroup; PartitionId = partitionId; InitialPosition = eventPosition; RetryPolicy = options.RetryOptions.ToRetryPolicy(); InnerConsumer = CreateTransportConsumer(consumerGroup, partitionId, eventPosition, RetryPolicy, options); }
/// <summary> /// Initializes a new instance of the <see cref="PartitionReceiver"/> class. /// </summary> /// /// <param name="consumerGroup">The name of the consumer group this client is associated with. Events are read in the context of this group.</param> /// <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 client should begin reading events.</param> /// <param name="connection">The <see cref="EventHubConnection" /> connection to use for communication with the Event Hubs service.</param> /// <param name="options">A set of options to apply when configuring the client.</param> /// public PartitionReceiver(string consumerGroup, string partitionId, EventPosition eventPosition, EventHubConnection connection, PartitionReceiverOptions options = default) { Argument.AssertNotNullOrEmpty(consumerGroup, nameof(consumerGroup)); Argument.AssertNotNullOrEmpty(partitionId, nameof(partitionId)); Argument.AssertNotNull(connection, nameof(connection)); options = options?.Clone() ?? new PartitionReceiverOptions(); OwnsConnection = false; Connection = connection; ConsumerGroup = consumerGroup; PartitionId = partitionId; InitialPosition = eventPosition; DefaultMaximumWaitTime = options.DefaultMaximumReceiveWaitTime; RetryPolicy = options.RetryOptions.ToRetryPolicy(); #pragma warning disable CA2214 // Do not call overridable methods in constructors. This internal method is virtual for testing purposes. InnerConsumer = CreateTransportConsumer(consumerGroup, partitionId, eventPosition, RetryPolicy, options); #pragma warning restore CA2214 // Do not call overridable methods in constructors. }
/// <summary> /// Begins the background process responsible for receiving from the specified <see cref="TransportConsumer" /> /// and publishing to the requested <see cref="Channel{PartitionEvent}" />. /// </summary> /// /// <param name="transportConsumer">The consumer to use for receiving events.</param> /// <param name="channel">The channel to which received events should be published.</param> /// <param name="partitionContext">The context that represents the partition from which events being received.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> to signal the request to cancel the background publishing.</param> /// /// <returns>A task to be resolved on when the operation has completed.</returns> /// private Task StartBackgroundChannelPublishingAsync(TransportConsumer transportConsumer, Channel <PartitionEvent> channel, PartitionContext partitionContext, CancellationToken cancellationToken) => Task.Run(async() => { var failedAttemptCount = 0; var receivedItems = default(IEnumerable <EventData>); var retryDelay = default(TimeSpan?); var activeException = default(Exception); while (!cancellationToken.IsCancellationRequested) { try { // Receive items in batches and then write them to the subscribed channels. The channels will naturally // block if they reach their maximum queue size, so there is no need to throttle publishing. receivedItems = await transportConsumer.ReceiveAsync(BackgroundPublishReceiveBatchSize, BackgroundPublishingWaitTime, cancellationToken).ConfigureAwait(false); foreach (EventData item in receivedItems) { await channel.Writer.WriteAsync(new PartitionEvent(partitionContext, item), cancellationToken).ConfigureAwait(false); } failedAttemptCount = 0; } catch (TaskCanceledException ex) { // In the case that a task was canceled, if cancellation was requested, then publishing should // is already terminating. Otherwise, something unexpected canceled the operation and it should // be treated as an exception to ensure that the channels are marked final and consumers are made // aware. activeException = (cancellationToken.IsCancellationRequested) ? null : ex; break; } catch (ConsumerDisconnectedException ex) { // If the consumer was disconnected, it is known to be unrecoverable; do not offer the chance to retry. activeException = ex; break; } catch (Exception ex) when (ex is OutOfMemoryException || ex is StackOverflowException || ex is ThreadAbortException) { channel.Writer.TryComplete(ex); throw; } catch (Exception ex) { // Determine if there should be a retry for the next attempt; if so enforce the delay but do not quit the loop. // Otherwise, mark the exception as active and break out of the loop. ++failedAttemptCount; retryDelay = RetryPolicy.CalculateRetryDelay(ex, failedAttemptCount); if (retryDelay.HasValue) { await Task.Delay(retryDelay.Value).ConfigureAwait(false); activeException = null; } else { activeException = ex; break; } } } // Publishing has terminated; if there was an active exception, then take the necessary steps to mark publishing as aborted rather // than completed normally. if (activeException != null) { channel.Writer.TryComplete(activeException); } }, cancellationToken);