Example #1
0
        /// <summary>
        ///   Initializes a new instance of the <see cref="AmqpProducer"/> class.
        /// </summary>
        ///
        /// <param name="eventHubName">The name of the Event Hub to which events will be published.</param>
        /// <param name="partitionId">The identifier of the Event Hub partition to which it is bound; if unbound, <c>null</c>.</param>
        /// <param name="connectionScope">The AMQP connection context for operations.</param>
        /// <param name="messageConverter">The converter to use for translating between AMQP messages and client types.</param>
        /// <param name="retryPolicy">The retry policy to consider when an operation fails.</param>
        ///
        /// <remarks>
        ///   As an internal type, this class performs only basic sanity checks against its arguments.  It
        ///   is assumed that callers are trusted and have performed deep validation.
        ///
        ///   Any parameters passed are assumed to be owned by this instance and safe to mutate or dispose;
        ///   creation of clones or otherwise protecting the parameters is assumed to be the purview of the
        ///   caller.
        /// </remarks>
        ///
        public AmqpProducer(string eventHubName,
                            string partitionId,
                            AmqpConnectionScope connectionScope,
                            AmqpMessageConverter messageConverter,
                            EventHubsRetryPolicy retryPolicy)
        {
            Argument.AssertNotNullOrEmpty(eventHubName, nameof(eventHubName));
            Argument.AssertNotNull(connectionScope, nameof(connectionScope));
            Argument.AssertNotNull(messageConverter, nameof(messageConverter));
            Argument.AssertNotNull(retryPolicy, nameof(retryPolicy));

            EventHubName     = eventHubName;
            PartitionId      = partitionId;
            RetryPolicy      = retryPolicy;
            ConnectionScope  = connectionScope;
            MessageConverter = messageConverter;

            SendLink = new FaultTolerantAmqpObject <SendingAmqpLink>(
                timeout => CreateLinkAndEnsureProducerStateAsync(partitionId, timeout, CancellationToken.None),
                link =>
            {
                link.Session?.SafeClose();
                link.SafeClose();
            });
        }
 /// <summary>
 ///   Creates a consumer strongly aligned with the active protocol and transport, responsible
 ///   for reading <see cref="EventData" /> from a specific Event Hub partition, in the context
 ///   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 by setting the <paramref name="ownerLevel" />.
 ///   When <c>null</c>, consumers are created as non-exclusive.
 /// </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="retryPolicy">The policy which governs retry behavior and try timeouts.</param>
 /// <param name="trackLastEnqueuedEventProperties">Indicates whether information on the last enqueued event on the partition is sent as events are received.</param>
 /// <param name="ownerLevel">The relative priority to associate with the link; for a non-exclusive link, this value should be <c>null</c>.</param>
 /// <param name="prefetchCount">Controls the number of events received and queued locally without regard to whether an operation was requested.  If <c>null</c> a default will be used.</param>
 ///
 /// <returns>A <see cref="TransportConsumer" /> configured in the requested manner.</returns>
 ///
 public abstract TransportConsumer CreateConsumer(string consumerGroup,
                                                  string partitionId,
                                                  EventPosition eventPosition,
                                                  EventHubsRetryPolicy retryPolicy,
                                                  bool trackLastEnqueuedEventProperties,
                                                  long?ownerLevel,
                                                  uint?prefetchCount);
        /// <summary>
        ///   Initializes a new instance of the <see cref="AmqpConsumer"/> class.
        /// </summary>
        ///
        /// <param name="eventHubName">The name of the Event Hub from which events will be consumed.</param>
        /// <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="consumerOptions">The set of active options for the consumer that will make use of the link.</param>
        /// <param name="eventPosition">The position of the event in the partition where the consumer should begin reading.</param>
        /// <param name="connectionScope">The AMQP connection context for operations .</param>
        /// <param name="messageConverter">The converter to use for translating between AMQP messages and client types.</param>
        /// <param name="retryPolicy">The retry policy to consider when an operation fails.</param>
        ///
        /// <remarks>
        ///   As an internal type, this class performs only basic sanity checks against its arguments.  It
        ///   is assumed that callers are trusted and have performed deep validation.
        ///
        ///   Any parameters passed are assumed to be owned by this instance and safe to mutate or dispose;
        ///   creation of clones or otherwise protecting the parameters is assumed to be the purview of the
        ///   caller.
        /// </remarks>
        ///
        public AmqpConsumer(string eventHubName,
                            string consumerGroup,
                            string partitionId,
                            EventPosition eventPosition,
                            EventHubConsumerClientOptions consumerOptions,
                            AmqpConnectionScope connectionScope,
                            AmqpMessageConverter messageConverter,
                            EventHubsRetryPolicy retryPolicy)
        {
            Argument.AssertNotNullOrEmpty(eventHubName, nameof(eventHubName));
            Argument.AssertNotNullOrEmpty(consumerGroup, nameof(consumerGroup));
            Argument.AssertNotNullOrEmpty(partitionId, nameof(partitionId));
            Argument.AssertNotNull(consumerOptions, nameof(EventHubConsumerClientOptions));
            Argument.AssertNotNull(connectionScope, nameof(connectionScope));
            Argument.AssertNotNull(messageConverter, nameof(messageConverter));
            Argument.AssertNotNull(retryPolicy, nameof(retryPolicy));

            EventHubName     = eventHubName;
            ConsumerGroup    = consumerGroup;
            PartitionId      = partitionId;
            Options          = consumerOptions;
            ConnectionScope  = connectionScope;
            RetryPolicy      = retryPolicy;
            MessageConverter = messageConverter;
            ReceiveLink      = new FaultTolerantAmqpObject <ReceivingAmqpLink>(timeout => ConnectionScope.OpenConsumerLinkAsync(consumerGroup, partitionId, eventPosition, consumerOptions, timeout, CancellationToken.None), link => link.SafeClose());
        }
Example #4
0
 internal override Task <PartitionProperties> GetPartitionPropertiesAsync(string partitionId,
                                                                          EventHubsRetryPolicy retryPolicy,
                                                                          CancellationToken cancellationToken = default)
 {
     GetPartitionPropertiesInvokedWith = retryPolicy;
     return(Task.FromResult(default(PartitionProperties)));
 }
 public override Task <PartitionProperties> GetPartitionPropertiesAsync(string partitionId,
                                                                        EventHubsRetryPolicy retryPolicy,
                                                                        CancellationToken cancellationToken = default)
 {
     GetPartitionPropertiesCalledForId = partitionId;
     return(Task.FromResult(default(PartitionProperties)));
 }
        /// <summary>
        ///   Initializes a new instance of the <see cref="AmqpProducer"/> class.
        /// </summary>
        ///
        /// <param name="eventHubName">The name of the Event Hub to which events will be published.</param>
        /// <param name="partitionId">The identifier of the Event Hub partition to which it is bound; if unbound, <c>null</c>.</param>
        /// <param name="connectionScope">The AMQP connection context for operations.</param>
        /// <param name="messageConverter">The converter to use for translating between AMQP messages and client types.</param>
        /// <param name="retryPolicy">The retry policy to consider when an operation fails.</param>
        /// <param name="requestedFeatures">The flags specifying the set of special transport features that should be opted-into.</param>
        /// <param name="partitionOptions">The set of options, if any, that should be considered when initializing the producer.</param>
        ///
        /// <remarks>
        ///   As an internal type, this class performs only basic sanity checks against its arguments.  It
        ///   is assumed that callers are trusted and have performed deep validation.
        ///
        ///   Any parameters passed are assumed to be owned by this instance and safe to mutate or dispose;
        ///   creation of clones or otherwise protecting the parameters is assumed to be the purview of the
        ///   caller.
        /// </remarks>
        ///
        public AmqpProducer(string eventHubName,
                            string partitionId,
                            AmqpConnectionScope connectionScope,
                            AmqpMessageConverter messageConverter,
                            EventHubsRetryPolicy retryPolicy,
                            TransportProducerFeatures requestedFeatures = TransportProducerFeatures.None,
                            PartitionPublishingOptions partitionOptions = null)
        {
            Argument.AssertNotNullOrEmpty(eventHubName, nameof(eventHubName));
            Argument.AssertNotNull(connectionScope, nameof(connectionScope));
            Argument.AssertNotNull(messageConverter, nameof(messageConverter));
            Argument.AssertNotNull(retryPolicy, nameof(retryPolicy));

            EventHubName     = eventHubName;
            PartitionId      = partitionId;
            RetryPolicy      = retryPolicy;
            ConnectionScope  = connectionScope;
            MessageConverter = messageConverter;
            ActiveFeatures   = requestedFeatures;
            ActiveOptions    = partitionOptions?.Clone() ?? new PartitionPublishingOptions();

            SendLink = new FaultTolerantAmqpObject <SendingAmqpLink>(
                timeout => CreateLinkAndEnsureProducerStateAsync(partitionId, ActiveOptions, timeout, CancellationToken.None),
                link =>
            {
                link.Session?.SafeClose();
                link.SafeClose();
            });
        }
Example #7
0
        /// <summary>
        ///   Creates a consumer strongly aligned with the active protocol and transport, responsible
        ///   for reading <see cref="EventData" /> from a specific Event Hub partition, in the context
        ///   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 by setting the <paramref name="ownerLevel" />.
        ///   When <c>null</c>, consumers are created as non-exclusive.
        /// </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="consumerIdentifier">The identifier to associate with the consumer; if <c>null</c> or <see cref="string.Empty" />, a random identifier will be generated.</param>
        /// <param name="eventPosition">The position within the partition where the consumer should begin reading events.</param>
        /// <param name="retryPolicy">The policy which governs retry behavior and try timeouts.</param>
        /// <param name="trackLastEnqueuedEventProperties">Indicates whether information on the last enqueued event on the partition is sent as events are received.</param>
        /// <param name="invalidateConsumerWhenPartitionStolen">Indicates whether or not the consumer should consider itself invalid when a partition is stolen.</param>
        /// <param name="ownerLevel">The relative priority to associate with the link; for a non-exclusive link, this value should be <c>null</c>.</param>
        /// <param name="prefetchCount">Controls the number of events received and queued locally without regard to whether an operation was requested.  If <c>null</c> a default will be used.</param>
        /// <param name="prefetchSizeInBytes">The cache size of the prefetch queue. When set, the link makes a best effort to ensure prefetched messages fit into the specified size.</param>
        ///
        /// <returns>A <see cref="TransportConsumer" /> configured in the requested manner.</returns>
        ///
        public override TransportConsumer CreateConsumer(string consumerGroup,
                                                         string partitionId,
                                                         string consumerIdentifier,
                                                         EventPosition eventPosition,
                                                         EventHubsRetryPolicy retryPolicy,
                                                         bool trackLastEnqueuedEventProperties,
                                                         bool invalidateConsumerWhenPartitionStolen,
                                                         long?ownerLevel,
                                                         uint?prefetchCount,
                                                         long?prefetchSizeInBytes)
        {
            Argument.AssertNotClosed(_closed, nameof(AmqpClient));

            return(new AmqpConsumer
                   (
                       EventHubName,
                       consumerGroup,
                       partitionId,
                       consumerIdentifier,
                       eventPosition,
                       trackLastEnqueuedEventProperties,
                       invalidateConsumerWhenPartitionStolen,
                       ownerLevel,
                       prefetchCount,
                       prefetchSizeInBytes,
                       ConnectionScope,
                       MessageConverter,
                       retryPolicy
                   ));
        }
Example #8
0
 /// <summary>
 ///   Initializes a new instance of the <see cref="BlobsCheckpointStore" /> class.
 /// </summary>
 ///
 /// <param name="blobContainerClient">The client used to interact with the Azure Blob Storage service.</param>
 /// <param name="retryPolicy">The retry policy to use as the basis for interacting with the Storage Blobs service.</param>
 /// <param name="functionId">The function id for diagnostic messages.</param>
 /// <param name="logger">The logger to use for diagnostic messages.</param>
 ///
 public BlobsCheckpointStore(BlobContainerClient blobContainerClient,
                             EventHubsRetryPolicy retryPolicy,
                             string functionId,
                             ILogger logger) : this(blobContainerClient, retryPolicy, initializeWithLegacyCheckpoints : true)
 {
     _functionId = functionId;
     _logger     = logger;
 }
Example #9
0
 /// <summary>
 ///   Initializes a new instance of the <see cref="BlobsCheckpointStore" /> class.
 /// </summary>
 ///
 /// <param name="blobContainerClient">The client used to interact with the Azure Blob Storage service.</param>
 /// <param name="retryPolicy">The retry policy to use as the basis for interacting with the Storage Blobs service.</param>
 /// <param name="functionId">The function id for diagnostic messages.</param>
 /// <param name="logger">The logger to use for diagnostic messages.</param>
 ///
 public BlobsCheckpointStore(BlobContainerClient blobContainerClient,
                             EventHubsRetryPolicy retryPolicy,
                             string functionId,
                             ILogger logger) : this(blobContainerClient, retryPolicy)
 {
     _functionId = functionId;
     _logger     = logger;
 }
 /// <summary>
 ///   Creates a consumer strongly aligned with the active protocol and transport, responsible
 ///   for reading <see cref="EventData" /> from a specific Event Hub partition, in the context
 ///   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 by setting the <paramref name="ownerLevel" />.
 ///   When <c>null</c>, consumers are created as non-exclusive.
 /// </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="retryPolicy">The policy which governs retry behavior and try timeouts.</param>
 /// <param name="trackLastEnqueuedEventProperties">Indicates whether information on the last enqueued event on the partition is sent as events are received.</param>
 /// <param name="invalidateConsumerWhenPartitionStolen">Indicates whether or not the consumer should consider itself invalid when a partition is stolen.</param>
 /// <param name="ownerLevel">The relative priority to associate with the link; for a non-exclusive link, this value should be <c>null</c>.</param>
 /// <param name="prefetchCount">Controls the number of events received and queued locally without regard to whether an operation was requested.  If <c>null</c> a default will be used.</param>
 /// <param name="prefetchSizeInBytes">The cache size of the prefetch queue. When set, the link makes a best effort to ensure prefetched messages fit into the specified size.</param>
 ///
 /// <returns>A <see cref="TransportConsumer" /> configured in the requested manner.</returns>
 ///
 public abstract TransportConsumer CreateConsumer(string consumerGroup,
                                                  string partitionId,
                                                  EventPosition eventPosition,
                                                  EventHubsRetryPolicy retryPolicy,
                                                  bool trackLastEnqueuedEventProperties,
                                                  bool invalidateConsumerWhenPartitionStolen,
                                                  long?ownerLevel,
                                                  uint?prefetchCount,
                                                  long?prefetchSizeInBytes);
        /// <summary>
        ///   Initializes a new instance of the <see cref="BlobsCheckpointStore"/> class.
        /// </summary>
        ///
        /// <param name="blobContainerClient">The client used to interact with the Azure Blob Storage service.</param>
        /// <param name="retryPolicy">The retry policy to use as the basis for interacting with the Storage Blobs service.</param>
        ///
        public BlobsCheckpointStore(BlobContainerClient blobContainerClient,
                                    EventHubsRetryPolicy retryPolicy)
        {
            Argument.AssertNotNull(blobContainerClient, nameof(blobContainerClient));
            Argument.AssertNotNull(retryPolicy, nameof(retryPolicy));

            ContainerClient = blobContainerClient;
            RetryPolicy     = retryPolicy;
        }
Example #12
0
        /// <summary>
        ///   Initializes a new instance of the <see cref="BlobsCheckpointStore" /> class.
        /// </summary>
        ///
        /// <param name="blobContainerClient">The client used to interact with the Azure Blob Storage service.</param>
        /// <param name="retryPolicy">The retry policy to use as the basis for interacting with the Storage Blobs service.</param>
        ///
        public BlobsCheckpointStore(BlobContainerClient blobContainerClient,
                                    EventHubsRetryPolicy retryPolicy)
        {
            Argument.AssertNotNull(blobContainerClient, nameof(blobContainerClient));
            Argument.AssertNotNull(retryPolicy, nameof(retryPolicy));

            ContainerClient = blobContainerClient;
            RetryPolicy     = retryPolicy;
            BlobsCheckpointStoreCreated(nameof(BlobsCheckpointStore), blobContainerClient.AccountName, blobContainerClient.Name);
        }
        /// <summary>
        ///   Initializes a new instance of the <see cref="BlobsCheckpointStore" /> class.
        /// </summary>
        ///
        /// <param name="blobContainerClient">The client used to interact with the Azure Blob Storage service.</param>
        /// <param name="retryPolicy">The retry policy to use as the basis for interacting with the Storage Blobs service.</param>
        /// <param name="initializeWithLegacyCheckpoints">Indicates whether to read legacy checkpoint when no current version checkpoint is available for a partition.</param>
        ///
        public BlobsCheckpointStore(BlobContainerClient blobContainerClient,
                                    EventHubsRetryPolicy retryPolicy,
                                    bool initializeWithLegacyCheckpoints = false)
        {
            Argument.AssertNotNull(blobContainerClient, nameof(blobContainerClient));
            Argument.AssertNotNull(retryPolicy, nameof(retryPolicy));

            ContainerClient = blobContainerClient;
            RetryPolicy     = retryPolicy;
            InitializeWithLegacyCheckpoints = initializeWithLegacyCheckpoints;
            BlobsCheckpointStoreCreated(nameof(BlobsCheckpointStore), blobContainerClient.AccountName, blobContainerClient.Name);
        }
        /// <summary>
        ///   Initializes a new instance of the <see cref="AmqpConsumer"/> class.
        /// </summary>
        ///
        /// <param name="eventHubName">The name of the Event Hub from which events will be consumed.</param>
        /// <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="consumerIdentifier">The identifier to associate with the consumer; if <c>null</c> or <see cref="string.Empty" />, a random identifier will be generated.</param>
        /// <param name="eventPosition">The position of the event in the partition where the consumer should begin reading.</param>
        /// <param name="prefetchCount">Controls the number of events received and queued locally without regard to whether an operation was requested.  If <c>null</c> a default will be used.</param>
        /// <param name="prefetchSizeInBytes">The cache size of the prefetch queue. When set, the link makes a best effort to ensure prefetched messages fit into the specified size.</param>
        /// <param name="ownerLevel">The relative priority to associate with the link; for a non-exclusive link, this value should be <c>null</c>.</param>
        /// <param name="trackLastEnqueuedEventProperties">Indicates whether information on the last enqueued event on the partition is sent as events are received.</param>
        /// <param name="invalidateConsumerWhenPartitionStolen">Indicates whether or not the consumer should consider itself invalid when a partition is stolen.</param>
        /// <param name="connectionScope">The AMQP connection context for operations .</param>
        /// <param name="messageConverter">The converter to use for translating between AMQP messages and client types.</param>
        /// <param name="retryPolicy">The retry policy to consider when an operation fails.</param>
        ///
        /// <remarks>
        ///   As an internal type, this class performs only basic sanity checks against its arguments.  It
        ///   is assumed that callers are trusted and have performed deep validation.
        ///
        ///   Any parameters passed are assumed to be owned by this instance and safe to mutate or dispose;
        ///   creation of clones or otherwise protecting the parameters is assumed to be the purview of the
        ///   caller.
        /// </remarks>
        ///
        public AmqpConsumer(string eventHubName,
                            string consumerGroup,
                            string partitionId,
                            string consumerIdentifier,
                            EventPosition eventPosition,
                            bool trackLastEnqueuedEventProperties,
                            bool invalidateConsumerWhenPartitionStolen,
                            long?ownerLevel,
                            uint?prefetchCount,
                            long?prefetchSizeInBytes,
                            AmqpConnectionScope connectionScope,
                            AmqpMessageConverter messageConverter,
                            EventHubsRetryPolicy retryPolicy)
        {
            Argument.AssertNotNullOrEmpty(eventHubName, nameof(eventHubName));
            Argument.AssertNotNullOrEmpty(consumerGroup, nameof(consumerGroup));
            Argument.AssertNotNullOrEmpty(partitionId, nameof(partitionId));
            Argument.AssertNotNull(connectionScope, nameof(connectionScope));
            Argument.AssertNotNull(messageConverter, nameof(messageConverter));
            Argument.AssertNotNull(retryPolicy, nameof(retryPolicy));

            if (string.IsNullOrEmpty(consumerIdentifier))
            {
                consumerIdentifier = Guid.NewGuid().ToString();
            }

            EventHubName                          = eventHubName;
            ConsumerGroup                         = consumerGroup;
            PartitionId                           = partitionId;
            Identifier                            = consumerIdentifier;
            CurrentEventPosition                  = eventPosition;
            TrackLastEnqueuedEventProperties      = trackLastEnqueuedEventProperties;
            InvalidateConsumerWhenPartitionStolen = invalidateConsumerWhenPartitionStolen;
            ConnectionScope                       = connectionScope;
            RetryPolicy                           = retryPolicy;
            MessageConverter                      = messageConverter;

            ReceiveLink = new FaultTolerantAmqpObject <ReceivingAmqpLink>(
                timeout =>
                CreateConsumerLinkAsync(
                    consumerGroup,
                    partitionId,
                    consumerIdentifier,
                    CurrentEventPosition,
                    prefetchCount ?? DefaultPrefetchCount,
                    prefetchSizeInBytes,
                    ownerLevel,
                    trackLastEnqueuedEventProperties,
                    timeout,
                    CancellationToken.None),
                CloseConsumerLink);
        }
Example #15
0
        /// <summary>
        ///   Creates a producer strongly aligned with the active protocol and transport,
        ///   responsible for publishing <see cref="EventData" /> to the Event Hub.
        /// </summary>
        ///
        /// <param name="partitionId">The identifier of the partition to which the transport producer should be bound; if <c>null</c>, the producer is unbound.</param>
        /// <param name="retryPolicy">The policy which governs retry behavior and try timeouts.</param>
        ///
        /// <returns>A <see cref="TransportProducer"/> configured in the requested manner.</returns>
        ///
        public override TransportProducer CreateProducer(string partitionId,
                                                         EventHubsRetryPolicy retryPolicy)
        {
            Argument.AssertNotClosed(_closed, nameof(AmqpClient));

            return(new AmqpProducer
                   (
                       EventHubName,
                       partitionId,
                       ConnectionScope,
                       MessageConverter,
                       retryPolicy
                   ));
        }
Example #16
0
        /// <summary>
        ///   Initializes a new instance of the <see cref="AmqpConsumer"/> class.
        /// </summary>
        ///
        /// <param name="eventHubName">The name of the Event Hub from which events will be consumed.</param>
        /// <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 of the event in the partition where the consumer should begin reading.</param>
        /// <param name="prefetchCount">Controls the number of events received and queued locally without regard to whether an operation was requested.  If <c>null</c> a default will be used.</param>
        /// <param name="prefetchSizeInBytes">The cache size of the prefetch queue. When set, the link makes a best effort to ensure prefetched messages fit into the specified size.</param>
        /// <param name="ownerLevel">The relative priority to associate with the link; for a non-exclusive link, this value should be <c>null</c>.</param>
        /// <param name="trackLastEnqueuedEventProperties">Indicates whether information on the last enqueued event on the partition is sent as events are received.</param>
        /// <param name="connectionScope">The AMQP connection context for operations .</param>
        /// <param name="messageConverter">The converter to use for translating between AMQP messages and client types.</param>
        /// <param name="retryPolicy">The retry policy to consider when an operation fails.</param>
        ///
        /// <remarks>
        ///   As an internal type, this class performs only basic sanity checks against its arguments.  It
        ///   is assumed that callers are trusted and have performed deep validation.
        ///
        ///   Any parameters passed are assumed to be owned by this instance and safe to mutate or dispose;
        ///   creation of clones or otherwise protecting the parameters is assumed to be the purview of the
        ///   caller.
        /// </remarks>
        ///
        public AmqpConsumer(string eventHubName,
                            string consumerGroup,
                            string partitionId,
                            EventPosition eventPosition,
                            bool trackLastEnqueuedEventProperties,
                            long?ownerLevel,
                            uint?prefetchCount,
                            long?prefetchSizeInBytes,
                            AmqpConnectionScope connectionScope,
                            AmqpMessageConverter messageConverter,
                            EventHubsRetryPolicy retryPolicy)
        {
            Argument.AssertNotNullOrEmpty(eventHubName, nameof(eventHubName));
            Argument.AssertNotNullOrEmpty(consumerGroup, nameof(consumerGroup));
            Argument.AssertNotNullOrEmpty(partitionId, nameof(partitionId));
            Argument.AssertNotNull(connectionScope, nameof(connectionScope));
            Argument.AssertNotNull(messageConverter, nameof(messageConverter));
            Argument.AssertNotNull(retryPolicy, nameof(retryPolicy));

            EventHubName                     = eventHubName;
            ConsumerGroup                    = consumerGroup;
            PartitionId                      = partitionId;
            CurrentEventPosition             = eventPosition;
            TrackLastEnqueuedEventProperties = trackLastEnqueuedEventProperties;
            ConnectionScope                  = connectionScope;
            RetryPolicy                      = retryPolicy;
            MessageConverter                 = messageConverter;

            ReceiveLink = new FaultTolerantAmqpObject <ReceivingAmqpLink>(
                timeout =>
                CreateConsumerLinkAsync(
                    consumerGroup,
                    partitionId,
                    CurrentEventPosition,
                    prefetchCount ?? DefaultPrefetchCount,
                    prefetchSizeInBytes,
                    ownerLevel,
                    trackLastEnqueuedEventProperties,
                    timeout,
                    CancellationToken.None),
                link =>
            {
                link.Session?.SafeClose();
                link.SafeClose();
            });
        }
        /// <summary>
        ///   Initializes a new instance of the <see cref="TransportProducerPool" /> class.
        /// </summary>
        ///
        /// <param name="connection">The <see cref="EventHubConnection" /> connection to use for communication with the Event Hubs service.</param>
        /// <param name="retryPolicy">The policy to use for determining retry behavior for when an operation fails.</param>
        /// <param name="pool">The pool of <see cref="PoolItem" /> that is going to be used to store the partition specific <see cref="TransportProducer" />.</param>
        /// <param name="performExpirationPeriod">The period after which <see cref="CreateExpirationTimerCallback" /> is run. Overrides <see cref="DefaultPerformExpirationPeriod" />.</param>
        /// <param name="eventHubProducer">An abstracted Event Hub transport-specific producer that is associated with the Event Hub gateway rather than a specific partition.</param>
        ///
        public TransportProducerPool(EventHubConnection connection,
                                     EventHubsRetryPolicy retryPolicy,
                                     ConcurrentDictionary <string, PoolItem> pool = default,
                                     TimeSpan?performExpirationPeriod             = default,
                                     TransportProducer eventHubProducer           = default)
        {
            Connection  = connection;
            RetryPolicy = retryPolicy;
            Pool        = pool ?? new ConcurrentDictionary <string, PoolItem>();
            performExpirationPeriod ??= DefaultPerformExpirationPeriod;
            EventHubProducer = eventHubProducer ?? connection.CreateTransportProducer(null, retryPolicy);

            ExpirationTimer = new Timer(CreateExpirationTimerCallback(),
                                        null,
                                        performExpirationPeriod.Value,
                                        performExpirationPeriod.Value);
        }
Example #18
0
        public void RespectsConnectionOptionsForConsumer(string expectedPathName, string connectionString)
        {
            var             testEndpoint = new Uri("http://mycustomendpoint.com");
            EventHubOptions options      = new EventHubOptions
            {
                ConnectionOptions = new EventHubConnectionOptions
                {
                    CustomEndpointAddress = testEndpoint
                },
                RetryOptions = new EventHubsRetryOptions
                {
                    MaximumRetries = 10
                }
            };

            options.AddReceiver(expectedPathName, connectionString);

            var configuration = CreateConfiguration();
            var factory       = new EventHubClientFactory(configuration, Mock.Of <AzureComponentFactory>(), Options.Create(options), new DefaultNameResolver(configuration));

            var consumer       = factory.GetEventHubConsumerClient(expectedPathName, null, "consumer");
            var consumerClient = (EventHubConsumerClient)typeof(EventHubConsumerClientImpl)
                                 .GetField("_client", BindingFlags.NonPublic | BindingFlags.Instance)
                                 .GetValue(consumer);
            EventHubConnection connection = (EventHubConnection)typeof(EventHubConsumerClient)
                                            .GetProperty("Connection", BindingFlags.NonPublic | BindingFlags.Instance)
                                            .GetValue(consumerClient);
            EventHubConnectionOptions connectionOptions = (EventHubConnectionOptions)typeof(EventHubConnection)
                                                          .GetProperty("Options", BindingFlags.NonPublic | BindingFlags.Instance)
                                                          .GetValue(connection);

            Assert.AreEqual(testEndpoint, connectionOptions.CustomEndpointAddress);

            EventHubsRetryPolicy retryPolicy = (EventHubsRetryPolicy)typeof(EventHubConsumerClient)
                                               .GetProperty("RetryPolicy", BindingFlags.NonPublic | BindingFlags.Instance)
                                               .GetValue(consumerClient);

            // Reflection was still necessary here because BasicRetryOptions (which is the concrete derived type)
            // is internal.
            EventHubsRetryOptions retryOptions = (EventHubsRetryOptions)retryPolicy.GetType()
                                                 .GetProperty("Options", BindingFlags.Public | BindingFlags.Instance)
                                                 .GetValue(retryPolicy);

            Assert.AreEqual(10, retryOptions.MaximumRetries);
            Assert.AreEqual(expectedPathName, consumer.EventHubName);
        }
Example #19
0
        /// <summary>
        ///   Creates a producer strongly aligned with the active protocol and transport,
        ///   responsible for publishing <see cref="EventData" /> to the Event Hub.
        /// </summary>
        ///
        /// <param name="partitionId">The identifier of the partition to which the transport producer should be bound; if <c>null</c>, the producer is unbound.</param>
        /// <param name="requestedFeatures">The flags specifying the set of special transport features that should be opted-into.</param>
        /// <param name="partitionOptions">The set of options, if any, that should be considered when initializing the producer.</param>
        /// <param name="retryPolicy">The policy which governs retry behavior and try timeouts.</param>
        ///
        /// <returns>A <see cref="TransportProducer"/> configured in the requested manner.</returns>
        ///
        public override TransportProducer CreateProducer(string partitionId,
                                                         TransportProducerFeatures requestedFeatures,
                                                         PartitionPublishingOptions partitionOptions,
                                                         EventHubsRetryPolicy retryPolicy)
        {
            Argument.AssertNotClosed(_closed, nameof(AmqpClient));

            return(new AmqpProducer
                   (
                       EventHubName,
                       partitionId,
                       ConnectionScope,
                       MessageConverter,
                       retryPolicy,
                       requestedFeatures,
                       partitionOptions
                   ));
        }
        /// <summary>
        ///   Initializes a new instance of the <see cref="AmqpProducer"/> class.
        /// </summary>
        ///
        /// <param name="eventHubName">The name of the Event Hub to which events will be published.</param>
        /// <param name="partitionId">The identifier of the Event Hub partition to which it is bound; if unbound, <c>null</c>.</param>
        /// <param name="producerIdentifier">The identifier to associate with the consumer; if <c>null</c> or <see cref="string.Empty" />, a random identifier will be generated.</param>
        /// <param name="connectionScope">The AMQP connection context for operations.</param>
        /// <param name="messageConverter">The converter to use for translating between AMQP messages and client types.</param>
        /// <param name="retryPolicy">The retry policy to consider when an operation fails.</param>
        /// <param name="requestedFeatures">The flags specifying the set of special transport features that should be opted-into.</param>
        /// <param name="partitionOptions">The set of options, if any, that should be considered when initializing the producer.</param>
        ///
        /// <remarks>
        ///   As an internal type, this class performs only basic sanity checks against its arguments.  It
        ///   is assumed that callers are trusted and have performed deep validation.
        ///
        ///   Any parameters passed are assumed to be owned by this instance and safe to mutate or dispose;
        ///   creation of clones or otherwise protecting the parameters is assumed to be the purview of the
        ///   caller.
        /// </remarks>
        ///
        public AmqpProducer(string eventHubName,
                            string partitionId,
                            string producerIdentifier,
                            AmqpConnectionScope connectionScope,
                            AmqpMessageConverter messageConverter,
                            EventHubsRetryPolicy retryPolicy,
                            TransportProducerFeatures requestedFeatures         = TransportProducerFeatures.None,
                            PartitionPublishingOptionsInternal partitionOptions = null)
        {
            Argument.AssertNotNullOrEmpty(eventHubName, nameof(eventHubName));
            Argument.AssertNotNull(connectionScope, nameof(connectionScope));
            Argument.AssertNotNull(messageConverter, nameof(messageConverter));
            Argument.AssertNotNull(retryPolicy, nameof(retryPolicy));

            if (string.IsNullOrEmpty(producerIdentifier))
            {
                producerIdentifier = Guid.NewGuid().ToString();
            }

            EventHubName     = eventHubName;
            PartitionId      = partitionId;
            Identifier       = producerIdentifier;
            RetryPolicy      = retryPolicy;
            ConnectionScope  = connectionScope;
            MessageConverter = messageConverter;
            ActiveFeatures   = requestedFeatures;
            ActiveOptions    = partitionOptions?.Clone() ?? new PartitionPublishingOptionsInternal();

            SendLink = new FaultTolerantAmqpObject <SendingAmqpLink>(
                timeout => CreateLinkAndEnsureProducerStateAsync(partitionId, producerIdentifier, ActiveOptions, timeout, CancellationToken.None),
                link =>
            {
                link.Session?.SafeClose();
                link.SafeClose();
                EventHubsEventSource.Log.FaultTolerantAmqpObjectClose(nameof(SendingAmqpLink), "", EventHubName, "", PartitionId, link.TerminalException?.Message);
            });
        }
Example #21
0
        /// <summary>
        ///   Creates a consumer strongly aligned with the active protocol and transport, responsible
        ///   for reading <see cref="EventData" /> from a specific Event Hub partition, in the context
        ///   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 by setting the <paramref name="ownerLevel" />.
        ///   When <c>null</c>, consumers are created as non-exclusive.
        /// </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="retryPolicy">The policy which governs retry behavior and try timeouts.</param>
        /// <param name="trackLastEnqueuedEventInformation">Indicates whether information on the last enqueued event on the partition is sent as events are received.</param>
        /// <param name="ownerLevel">The relative priority to associate with the link; for a non-exclusive link, this value should be <c>null</c>.</param>
        /// <param name="prefetchCount">Controls the number of events received and queued locally without regard to whether an operation was requested.  If <c>null</c> a default will be used.</param>
        ///
        /// <returns>A <see cref="TransportConsumer" /> configured in the requested manner.</returns>
        ///
        public override TransportConsumer CreateConsumer(string consumerGroup,
                                                         string partitionId,
                                                         EventPosition eventPosition,
                                                         EventHubsRetryPolicy retryPolicy,
                                                         bool trackLastEnqueuedEventInformation,
                                                         long?ownerLevel,
                                                         uint?prefetchCount)
        {
            Argument.AssertNotClosed(_closed, nameof(AmqpClient));

            return(new AmqpConsumer
                   (
                       EventHubName,
                       consumerGroup,
                       partitionId,
                       eventPosition,
                       trackLastEnqueuedEventInformation,
                       ownerLevel,
                       prefetchCount,
                       ConnectionScope,
                       MessageConverter,
                       retryPolicy
                   ));
        }
Example #22
0
        /// <summary>
        ///   Retrieves information about a specific partition for an Event Hub, including elements that describe the available
        ///   events in the partition event stream.
        /// </summary>
        ///
        /// <param name="partitionId">The unique identifier of a partition associated with the Event Hub.</param>
        /// <param name="retryPolicy">The retry policy to use as the basis for retrieving the information.</param>
        /// <param name="cancellationToken">An optional <see cref="CancellationToken"/> instance to signal the request to cancel the operation.</param>
        ///
        /// <returns>The set of information for the requested partition under the Event Hub this client is associated with.</returns>
        ///
        public override async Task <PartitionProperties> GetPartitionPropertiesAsync(string partitionId,
                                                                                     EventHubsRetryPolicy retryPolicy,
                                                                                     CancellationToken cancellationToken)
        {
            Argument.AssertNotClosed(_closed, nameof(AmqpClient));
            Argument.AssertNotNullOrEmpty(partitionId, nameof(partitionId));
            Argument.AssertNotNull(retryPolicy, nameof(retryPolicy));

            var failedAttemptCount = 0;
            var retryDelay         = default(TimeSpan?);
            var token = default(string);
            var link  = default(RequestResponseAmqpLink);

            var stopWatch = ValueStopwatch.StartNew();

            try
            {
                var tryTimeout = retryPolicy.CalculateTryTimeout(0);

                while (!cancellationToken.IsCancellationRequested)
                {
                    try
                    {
                        EventHubsEventSource.Log.GetPartitionPropertiesStart(EventHubName, partitionId);

                        // Create the request message and the management link.

                        token = await AcquireAccessTokenAsync(cancellationToken).ConfigureAwait(false);

                        using AmqpMessage request = MessageConverter.CreatePartitionPropertiesRequest(EventHubName, partitionId, token);

                        if (!ManagementLink.TryGetOpenedObject(out link))
                        {
                            link = await ManagementLink.GetOrCreateAsync(UseMinimum(ConnectionScope.SessionTimeout, tryTimeout.CalculateRemaining(stopWatch.GetElapsedTime())), cancellationToken).ConfigureAwait(false);
                        }

                        cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>();

                        // Send the request and process the response.

                        using AmqpMessage response = await link.RequestAsync(request, cancellationToken).ConfigureAwait(false);

                        AmqpError.ThrowIfErrorResponse(response, EventHubName);
                        return(MessageConverter.CreatePartitionPropertiesFromResponse(response));
                    }
                    catch (Exception ex)
                    {
                        Exception activeEx = ex.TranslateServiceException(EventHubName);

                        // 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(activeEx, failedAttemptCount);

                        if ((retryDelay.HasValue) && (!ConnectionScope.IsDisposed) && (!_closed) && (!cancellationToken.IsCancellationRequested))
                        {
                            EventHubsEventSource.Log.GetPartitionPropertiesError(EventHubName, partitionId, activeEx.Message);
                            await Task.Delay(retryDelay.Value, cancellationToken).ConfigureAwait(false);

                            tryTimeout = retryPolicy.CalculateTryTimeout(failedAttemptCount);
                            stopWatch  = ValueStopwatch.StartNew();
                        }
                        else if (ex is AmqpException)
                        {
                            ExceptionDispatchInfo.Capture(activeEx).Throw();
                        }
                        else
                        {
                            throw;
                        }
                    }
                }

                // If no value has been returned nor exception thrown by this point,
                // then cancellation has been requested.

                throw new TaskCanceledException();
            }
            catch (Exception ex)
            {
                EventHubsEventSource.Log.GetPartitionPropertiesError(EventHubName, partitionId, ex.Message);
                throw;
            }
            finally
            {
                EventHubsEventSource.Log.GetPartitionPropertiesComplete(EventHubName, partitionId);
            }
        }
Example #23
0
        /// <summary>
        ///   Creates a producer strongly aligned with the active protocol and transport,
        ///   responsible for publishing <see cref="EventData" /> to the Event Hub.
        /// </summary>
        ///
        /// <param name="partitionId">The identifier of the partition to which the transport producer should be bound; if <c>null</c>, the producer is unbound.</param>
        /// <param name="producerIdentifier">The identifier to associate with the consumer; if <c>null</c> or <see cref="string.Empty" />, a random identifier will be generated.</param>
        /// <param name="requestedFeatures">The flags specifying the set of special transport features that should be opted-into.</param>
        /// <param name="partitionOptions">The set of options, if any, that should be considered when initializing the producer.</param>
        /// <param name="retryPolicy">The policy which governs retry behavior and try timeouts.</param>

        ///
        /// <returns>A <see cref="TransportProducer"/> configured in the requested manner.</returns>
        ///
        public abstract TransportProducer CreateProducer(string partitionId,
                                                         string producerIdentifier,
                                                         TransportProducerFeatures requestedFeatures,
                                                         PartitionPublishingOptionsInternal partitionOptions,
                                                         EventHubsRetryPolicy retryPolicy);
 internal override TransportProducer CreateTransportProducer(string partitionId,
                                                             TransportProducerFeatures requestedFeatures,
                                                             PartitionPublishingOptions partitionOptions,
                                                             EventHubsRetryPolicy retryPolicy) => TransportProducerFactory();
 /// <summary>
 ///   Creates a producer strongly aligned with the active protocol and transport,
 ///   responsible for publishing <see cref="EventData" /> to the Event Hub.
 /// </summary>
 ///
 /// <param name="partitionId">The identifier of the partition to which the transport producer should be bound; if <c>null</c>, the producer is unbound.</param>
 /// <param name="retryPolicy">The policy which governs retry behavior and try timeouts.</param>
 ///
 /// <returns>A <see cref="TransportProducer"/> configured in the requested manner.</returns>
 ///
 public abstract TransportProducer CreateProducer(string partitionId,
                                                  EventHubsRetryPolicy retryPolicy);
 /// <summary>
 ///   Retrieves information about an Event Hub, including the number of partitions present
 ///   and their identifiers.
 /// </summary>
 ///
 /// <param name="retryPolicy">The retry policy to use as the basis for retrieving the information.</param>
 /// <param name="cancellationToken">An optional <see cref="CancellationToken"/> instance to signal the request to cancel the operation.</param>
 ///
 /// <returns>The set of information for the Event Hub that this client is associated with.</returns>
 ///
 public abstract Task <EventHubProperties> GetPropertiesAsync(EventHubsRetryPolicy retryPolicy,
                                                              CancellationToken cancellationToken);
Example #27
0
 internal override TransportProducer CreateTransportProducer(string partitionId,
                                                             EventHubsRetryPolicy retryPolicy) => TransportProducerFactory();
 /// <summary>
 ///   Retrieves information about a specific partition for an Event Hub, including elements that describe the available
 ///   events in the partition event stream.
 /// </summary>
 ///
 /// <param name="partitionId">The unique identifier of a partition associated with the Event Hub.</param>
 /// <param name="retryPolicy">The retry policy to use as the basis for retrieving the information.</param>
 /// <param name="cancellationToken">An optional <see cref="CancellationToken"/> instance to signal the request to cancel the operation.</param>
 ///
 /// <returns>The set of information for the requested partition under the Event Hub this client is associated with.</returns>
 ///
 public abstract Task <PartitionProperties> GetPartitionPropertiesAsync(string partitionId,
                                                                        EventHubsRetryPolicy retryPolicy,
                                                                        CancellationToken cancellationToken);
Example #29
0
 internal async override Task <string[]> GetPartitionIdsAsync(EventHubsRetryPolicy retryPolicy,
                                                              CancellationToken cancellationToken = default)
 {
     GetPartitionIdsInvokedWith = retryPolicy;
     return(await base.GetPartitionIdsAsync(retryPolicy, cancellationToken));
 }
Example #30
0
 internal override Task <EventHubProperties> GetPropertiesAsync(EventHubsRetryPolicy retryPolicy,
                                                                CancellationToken cancellationToken = default)
 {
     GetPropertiesInvokedWith = retryPolicy;
     return(Task.FromResult(new EventHubProperties(EventHubName, DateTimeOffset.Parse("2015-10-27T00:00:00Z"), new string[] { "0", "1" })));
 }