public void ConstructorSetsTheRetryPolicy() { EventHubRetryPolicy retryPolicy = Mock.Of <EventHubRetryPolicy>(); var producer = new EventHubProducer(new ObservableTransportProducerMock(), new Uri("amqp://some.endpoint.com/path"), "path", new EventHubProducerOptions(), retryPolicy); Assert.That(producer.RetryPolicy, Is.SameAs(retryPolicy)); }
public void SettingTheRetryUpdatesState() { var retryOptions = new RetryOptions { Delay = TimeSpan.FromSeconds(1), MaximumDelay = TimeSpan.FromSeconds(2), TryTimeout = TimeSpan.FromSeconds(3), MaximumRetries = 4, Mode = RetryMode.Fixed }; EventHubRetryPolicy customRetry = Mock.Of <EventHubRetryPolicy>(); var producerOptions = new EventHubProducerOptions { RetryOptions = retryOptions }; var producer = new EventHubProducer(new ObservableTransportProducerMock(), new Uri("amqp://some.endpoint.com/path"), "dummy", producerOptions, new BasicRetryPolicy(retryOptions)); Assert.That(producer.RetryPolicy, Is.InstanceOf <BasicRetryPolicy>(), "The retry policy should have been created from options"); producer.RetryPolicy = customRetry; Assert.That(producer.RetryPolicy, Is.SameAs(customRetry), "The custom retry policy should have been set."); var activeOptions = (EventHubProducerOptions) typeof(EventHubProducer) .GetProperty("Options", BindingFlags.Instance | BindingFlags.NonPublic) .GetValue(producer); Assert.That(activeOptions.RetryOptions, Is.Null, "Setting a custom policy should clear the retry options."); }
/// <summary> /// Updates the active retry policy for the client. /// </summary> /// /// <param name="newRetryPolicy">The retry policy to set as active.</param> /// public override void UpdateRetryPolicy(EventHubRetryPolicy newRetryPolicy) { Argument.AssertNotNull(newRetryPolicy, nameof(newRetryPolicy)); _retryPolicy = newRetryPolicy; _tryTimeout = _retryPolicy.CalculateTryTimeout(0); }
internal override Task <PartitionProperties> GetPartitionPropertiesAsync(string partitionId, EventHubRetryPolicy retryPolicy, CancellationToken cancellationToken = default) { GetPartitionPropertiesInvokedWith = retryPolicy; return(Task.FromResult(default(PartitionProperties))); }
/// <summary> /// Initializes a new instance of the <see cref="AmqpEventHubConsumer"/> 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 AmqpEventHubConsumer(string eventHubName, string consumerGroup, string partitionId, EventPosition eventPosition, EventHubConsumerOptions consumerOptions, AmqpConnectionScope connectionScope, AmqpMessageConverter messageConverter, EventHubRetryPolicy retryPolicy) { Argument.AssertNotNullOrEmpty(eventHubName, nameof(eventHubName)); Argument.AssertNotNullOrEmpty(consumerGroup, nameof(consumerGroup)); Argument.AssertNotNullOrEmpty(partitionId, nameof(partitionId)); Argument.AssertNotNull(eventPosition, nameof(EventPosition)); Argument.AssertNotNull(consumerOptions, nameof(EventHubConsumerOptions)); 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; MessageConverter = messageConverter; ReceiveLink = new FaultTolerantAmqpObject <ReceivingAmqpLink>(timeout => ConnectionScope.OpenConsumerLinkAsync(consumerGroup, partitionId, eventPosition, consumerOptions, timeout, CancellationToken.None), link => link.SafeClose()); _retryPolicy = retryPolicy; _tryTimeout = retryPolicy.CalculateTryTimeout(0); }
/// <summary> /// Updates the active retry policy for the client. /// </summary> /// /// <param name="newRetryPolicy">The retry policy to set as active.</param> /// public override void UpdateRetryPolicy(EventHubRetryPolicy newRetryPolicy) { Guard.ArgumentNotNull(nameof(newRetryPolicy), newRetryPolicy); _retryPolicy = newRetryPolicy; _tryTimeout = _retryPolicy.CalculateTryTimeout(0); }
public override Task <PartitionProperties> GetPartitionPropertiesAsync(string partitionId, EventHubRetryPolicy retryPolicy, CancellationToken cancellationToken = default) { GetPartitionPropertiesCalledForId = partitionId; return(Task.FromResult(default(PartitionProperties))); }
/// <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="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="consumerOptions">The set of options to apply when creating the consumer.</param> /// <param name="defaultRetryPolicy">The default retry policy to use if no retry options were specified in the <paramref name="consumerOptions" />.</param> /// /// <returns>An Event Hub consumer configured in the requested manner.</returns> /// public override EventHubConsumer CreateConsumer(string consumerGroup, string partitionId, EventPosition eventPosition, EventHubConsumerOptions consumerOptions, EventHubRetryPolicy defaultRetryPolicy) { Argument.AssertNotClosed(_closed, nameof(AmqpEventHubClient)); LastEnqueuedEventProperties lastEnqueuedEventProperties = consumerOptions.TrackLastEnqueuedEventInformation ? new LastEnqueuedEventProperties(EventHubName, partitionId) : null; EventHubRetryPolicy retryPolicy = defaultRetryPolicy ?? _retryPolicy; var transportConsumer = new AmqpEventHubConsumer ( EventHubName, consumerGroup, partitionId, eventPosition, consumerOptions, ConnectionScope, MessageConverter, retryPolicy, lastEnqueuedEventProperties ); return(new EventHubConsumer(transportConsumer, EventHubName, consumerGroup, partitionId, eventPosition, consumerOptions, retryPolicy)); }
/// <summary> /// Creates an Event Hub producer responsible for transmitting <see cref="EventData" /> to the /// Event Hub, grouped together in batches. Depending on the <paramref name="producerOptions"/> /// specified, the producer may be created to allow event data to be automatically routed to an available /// partition or specific to a partition. /// </summary> /// /// <param name="producerOptions">The set of options to apply when creating the producer.</param> /// <param name="defaultRetryPolicy">The default retry policy to use if no retry options were specified in the <paramref name="producerOptions" />.</param> /// /// <returns>An Event Hub producer configured in the requested manner.</returns> /// public override EventHubProducer CreateProducer(EventHubProducerOptions producerOptions, EventHubRetryPolicy defaultRetryPolicy) { TrackOne.EventDataSender CreateSenderFactory(EventHubRetryPolicy activeRetryPolicy) { var producer = TrackOneClient.CreateEventSender(producerOptions.PartitionId); producer.RetryPolicy = new TrackOneRetryPolicy(activeRetryPolicy); return(producer); } var initialRetryPolicy = (producerOptions.RetryOptions != null) ? new BasicRetryPolicy(producerOptions.RetryOptions) : defaultRetryPolicy; return(new EventHubProducer ( new TrackOneEventHubProducer(CreateSenderFactory, initialRetryPolicy), TrackOneClient.ConnectionStringBuilder.Endpoint, TrackOneClient.EventHubName, producerOptions, initialRetryPolicy )); }
/// <summary> /// Initializes a new instance of the <see cref="TrackOneEventHubClient"/> class. /// </summary> /// /// <param name="host">The fully qualified host name for the Event Hubs namespace. 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 connect the client to.</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="clientOptions">A set of options to apply when configuring the client.</param> /// <param name="defaultRetryPolicy">The default retry policy to use if no retry options were specified in the <paramref name="clientOptions" />.</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 TrackOneEventHubClient(string host, string eventHubName, TokenCredential credential, EventHubClientOptions clientOptions, EventHubRetryPolicy defaultRetryPolicy) : this(host, eventHubName, credential, clientOptions, defaultRetryPolicy, CreateClient) { }
/// <summary> /// Initializes a new instance of the <see cref="AmqpEventHubClient"/> class. /// </summary> /// /// <param name="host">The fully qualified host name for the Event Hubs namespace. 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 connect the client to.</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="clientOptions">A set of options to apply when configuring the client.</param> /// <param name="defaultRetryPolicy">The default retry policy to use if no retry options were specified in the <paramref name="clientOptions" />.</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 AmqpEventHubClient(string host, string eventHubName, TokenCredential credential, EventHubClientOptions clientOptions, EventHubRetryPolicy defaultRetryPolicy) : this(host, eventHubName, credential, clientOptions, defaultRetryPolicy, null, null) { }
public async Task ReceiverIsConstructedCorrectly() { var eventHub = "eventHub"; var consumerGroup = "$TestThing"; var partition = "123"; var position = EventPosition.FromEnqueuedTime(DateTimeOffset.Parse("2015-10-25T12:00:00Z")); var priority = 8765; var identifier = "ThisIsAnAwesomeConsumer!"; var partitionMetrics = new LastEnqueuedEventProperties(eventHub, partition); EventHubRetryPolicy retryPolicy = Mock.Of <EventHubRetryPolicy>(); var mock = new ObservableReceiverMock(new ClientMock(), consumerGroup, partition, TrackOne.EventPosition.FromEnqueuedTime(position.EnqueuedTime.Value.UtcDateTime), priority, new ReceiverOptions { Identifier = identifier, EnableReceiverRuntimeMetric = true }); var consumer = new TrackOneEventHubConsumer(_ => mock, retryPolicy, partitionMetrics); // Invoke an operation to force the consumer to be lazily instantiated. Otherwise, // construction does not happen. await consumer.ReceiveAsync(0, TimeSpan.Zero, default); Assert.That(mock.ConstructedWith.ConsumerGroup, Is.EqualTo(consumerGroup), "The consumer group should match."); Assert.That(mock.ConstructedWith.Partition, Is.EqualTo(partition), "The partition should match."); Assert.That(TrackOneComparer.IsEventPositionEquivalent(mock.ConstructedWith.Position, position), Is.True, "The starting event position should match."); Assert.That(mock.ConstructedWith.Priority, Is.EqualTo(priority), "The owner level should match."); Assert.That(mock.ConstructedWith.Options.Identifier, Is.EqualTo(identifier), "The consumer identifier should match."); Assert.That(mock.ConstructedWith.Options.EnableReceiverRuntimeMetric, Is.True, "The receiver metrics should be enabled when set in the options."); EventHubRetryPolicy consumerRetry = GetRetryPolicy(consumer); Assert.That(consumerRetry, Is.SameAs(retryPolicy), "The consumer retry instance should match."); }
public InjectableMockClient(string host, string eventHubName, TokenCredential credential, EventHubClientOptions clientOptions, EventHubRetryPolicy defaultRetryPolicy, AmqpConnectionScope connectionScope, AmqpMessageConverter messageConverter) : base(host, eventHubName, credential, clientOptions, defaultRetryPolicy, connectionScope, messageConverter) { }
/// <summary> /// Initializes a new instance of the <see cref="TrackOneEventHubProducer"/> class. /// </summary> /// /// <param name="trackOneSenderFactory">A delegate that can be used for creation of the <see cref="TrackOne.EventDataSender" /> to which operations are delegated to.</param> /// <param name="retryPolicy">The retry policy to use when creating the <see cref="TrackOne.EventDataSender" />.</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 TrackOneEventHubProducer(Func <EventHubRetryPolicy, TrackOne.EventDataSender> trackOneSenderFactory, EventHubRetryPolicy retryPolicy) { Argument.AssertNotNull(trackOneSenderFactory, nameof(trackOneSenderFactory)); Argument.AssertNotNull(retryPolicy, nameof(retryPolicy)); _retryPolicy = retryPolicy; _trackOneSender = new Lazy <TrackOne.EventDataSender>(() => trackOneSenderFactory(_retryPolicy), LazyThreadSafetyMode.ExecutionAndPublication); }
/// <summary> /// Creates a 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="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="consumerOptions">The set of options to apply when creating the consumer.</param> /// <param name="defaultRetryPolicy">The default retry policy to use if no retry options were specified in the <paramref name="consumerOptions" />.</param> /// /// <returns>An Event Hub consumer configured in the requested manner.</returns> /// public override EventHubConsumer CreateConsumer(string consumerGroup, string partitionId, EventPosition eventPosition, EventHubConsumerOptions consumerOptions, EventHubRetryPolicy defaultRetryPolicy) { TrackOne.PartitionReceiver CreateReceiverFactory(EventHubRetryPolicy activeRetryPolicy) { var position = new TrackOne.EventPosition { IsInclusive = eventPosition.IsInclusive, Offset = eventPosition.Offset, SequenceNumber = eventPosition.SequenceNumber, EnqueuedTimeUtc = eventPosition.EnqueuedTime?.UtcDateTime }; var trackOneOptions = new TrackOne.ReceiverOptions { Identifier = consumerOptions.Identifier, EnableReceiverRuntimeMetric = consumerOptions.TrackLastEnqueuedEventInformation }; PartitionReceiver consumer; if (consumerOptions.OwnerLevel.HasValue) { consumer = TrackOneClient.CreateEpochReceiver(consumerGroup, partitionId, position, consumerOptions.OwnerLevel.Value, trackOneOptions); } else { consumer = TrackOneClient.CreateReceiver(consumerGroup, partitionId, position, trackOneOptions); } consumer.RetryPolicy = new TrackOneRetryPolicy(activeRetryPolicy); return(consumer); } EventHubRetryPolicy initialRetryPolicy = (consumerOptions.RetryOptions != null) ? new BasicRetryPolicy(consumerOptions.RetryOptions) : defaultRetryPolicy; LastEnqueuedEventProperties partitionMetrics = (consumerOptions.TrackLastEnqueuedEventInformation) ? new LastEnqueuedEventProperties(EventHubName, partitionId) : null; return(new EventHubConsumer ( new TrackOneEventHubConsumer(CreateReceiverFactory, initialRetryPolicy, partitionMetrics), TrackOneClient.EventHubName, partitionId, consumerGroup, eventPosition, consumerOptions, initialRetryPolicy )); }
/// <summary> /// Updates the active retry policy for the client. /// </summary> /// /// <param name="newRetryPolicy">The retry policy to set as active.</param> /// public override void UpdateRetryPolicy(EventHubRetryPolicy newRetryPolicy) { _retryPolicy = newRetryPolicy; if (_trackOneSender.IsValueCreated) { TrackOneSender.RetryPolicy = new TrackOneRetryPolicy(newRetryPolicy); } }
/// <summary> /// Initializes a new instance of the <see cref="TrackOneEventHubConsumer"/> class. /// </summary> /// /// <param name="trackOneReceiverFactory">A delegate that can be used for creation of the <see cref="TrackOne.PartitionReceiver" /> to which operations are delegated to.</param> /// <param name="retryPolicy">The retry policy to use when creating the <see cref="TrackOne.PartitionReceiver" />.</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 TrackOneEventHubConsumer(Func <EventHubRetryPolicy, TrackOne.PartitionReceiver> trackOneReceiverFactory, EventHubRetryPolicy retryPolicy) { Guard.ArgumentNotNull(nameof(trackOneReceiverFactory), trackOneReceiverFactory); Guard.ArgumentNotNull(nameof(retryPolicy), retryPolicy); _retryPolicy = retryPolicy; _trackOneReceiver = new Lazy <TrackOne.PartitionReceiver>(() => trackOneReceiverFactory(_retryPolicy), LazyThreadSafetyMode.PublicationOnly); }
/// <summary> /// Initializes a new instance of the <see cref="TrackOneEventHubProducer"/> class. /// </summary> /// /// <param name="trackOneSenderFactory">A delegate that can be used for creation of the <see cref="TrackOne.EventDataSender" /> to which operations are delegated to.</param> /// <param name="retryPolicy">The retry policy to use when creating the <see cref="TrackOne.EventDataSender" />.</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 TrackOneEventHubProducer(Func <EventHubRetryPolicy, TrackOne.EventDataSender> trackOneSenderFactory, EventHubRetryPolicy retryPolicy) { Guard.ArgumentNotNull(nameof(trackOneSenderFactory), trackOneSenderFactory); Guard.ArgumentNotNull(nameof(retryPolicy), retryPolicy); _retryPolicy = retryPolicy; _trackOneSender = new Lazy <TrackOne.EventDataSender>(() => trackOneSenderFactory(_retryPolicy), LazyThreadSafetyMode.PublicationOnly); }
/// <summary> /// Updates the active retry policy for the client. /// </summary> /// /// <param name="newRetryPolicy">The retry policy to set as active.</param> /// public override void UpdateRetryPolicy(EventHubRetryPolicy newRetryPolicy) { _retryPolicy = newRetryPolicy; if (_trackOneClient.IsValueCreated) { TrackOneClient.RetryPolicy = new TrackOneRetryPolicy(newRetryPolicy); TrackOneClient.ConnectionStringBuilder.OperationTimeout = newRetryPolicy.CalculateTryTimeout(0); } }
/// <summary> /// Initializes a new instance of the <see cref="TrackOneEventHubConsumer"/> class. /// </summary> /// /// <param name="trackOneReceiverFactory">A delegate that can be used for creation of the <see cref="TrackOne.PartitionReceiver" /> to which operations are delegated to.</param> /// <param name="retryPolicy">The retry policy to use when creating the <see cref="TrackOne.PartitionReceiver" />.</param> /// <param name="lastEnqueuedEventProperties">The set of properties for the last event enqueued in a partition; if not requested in the consumer options, it is expected that this is <c>null</c>.</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 TrackOneEventHubConsumer(Func <EventHubRetryPolicy, TrackOne.PartitionReceiver> trackOneReceiverFactory, EventHubRetryPolicy retryPolicy, LastEnqueuedEventProperties lastEnqueuedEventProperties) : base(lastEnqueuedEventProperties) { Guard.ArgumentNotNull(nameof(trackOneReceiverFactory), trackOneReceiverFactory); Guard.ArgumentNotNull(nameof(retryPolicy), retryPolicy); _retryPolicy = retryPolicy; _trackOneReceiver = new Lazy <TrackOne.PartitionReceiver>(() => trackOneReceiverFactory(_retryPolicy), LazyThreadSafetyMode.ExecutionAndPublication); }
public void SettingTheRetryUpdatesTheTransportProducer() { EventHubRetryPolicy customRetry = Mock.Of <EventHubRetryPolicy>(); var transportProducer = new ObservableTransportProducerMock(); var producerOptions = new EventHubProducerOptions(); var producer = new EventHubProducer(transportProducer, new Uri("amqp://some.endpoint.com/path"), "dummy", producerOptions, Mock.Of <EventHubRetryPolicy>()) { RetryPolicy = customRetry }; Assert.That(transportProducer.UpdateRetryPolicyCalledWith, Is.SameAs(customRetry), "The custom retry policy should have been passed to the transport producer."); }
/// <summary> /// Initializes a new instance of the <see cref="TrackOneEventHubClient"/> class. /// </summary> /// /// <param name="host">The fully qualified host name for the Event Hubs namespace. 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 connect the client to.</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="clientOptions">A set of options to apply when configuring the client.</param> /// <param name="defaultRetryPolicy">The default retry policy to use if no retry options were specified in the <paramref name="clientOptions" />.</param> /// <param name="eventHubClientFactory">A delegate that can be used for creation of the <see cref="TrackOne.EventHubClient" /> to which operations are delegated to.</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 TrackOneEventHubClient(string host, string eventHubName, TokenCredential credential, EventHubClientOptions clientOptions, EventHubRetryPolicy defaultRetryPolicy, Func <string, string, TokenCredential, EventHubClientOptions, Func <EventHubRetryPolicy>, TrackOne.EventHubClient> eventHubClientFactory) { Guard.ArgumentNotNullOrEmpty(nameof(host), host); Guard.ArgumentNotNullOrEmpty(nameof(eventHubName), eventHubName); Guard.ArgumentNotNull(nameof(credential), credential); Guard.ArgumentNotNull(nameof(clientOptions), clientOptions); Guard.ArgumentNotNull(nameof(defaultRetryPolicy), defaultRetryPolicy); _retryPolicy = defaultRetryPolicy; _trackOneClient = new Lazy <TrackOne.EventHubClient>(() => eventHubClientFactory(host, eventHubName, credential, clientOptions, () => _retryPolicy), LazyThreadSafetyMode.ExecutionAndPublication); }
/// <summary> /// Creates an Event Hub producer responsible for transmitting <see cref="EventData" /> to the /// Event Hub, grouped together in batches. Depending on the <paramref name="producerOptions"/> /// specified, the producer may be created to allow event data to be automatically routed to an available /// partition or specific to a partition. /// </summary> /// /// <param name="producerOptions">The set of options to apply when creating the producer.</param> /// <param name="defaultRetryPolicy">The default retry policy to use if no retry options were specified in the <paramref name="producerOptions" />.</param> /// /// <returns>An Event Hub producer configured in the requested manner.</returns> /// public override EventHubProducer CreateProducer(EventHubProducerOptions producerOptions, EventHubRetryPolicy defaultRetryPolicy) { Argument.AssertNotClosed(_closed, nameof(AmqpEventHubClient)); EventHubRetryPolicy retryPolicy = defaultRetryPolicy ?? _retryPolicy; var transportProducer = new AmqpEventHubProducer ( EventHubName, producerOptions.PartitionId, ConnectionScope, MessageConverter, retryPolicy ); return(new EventHubProducer(transportProducer, ServiceEndpoint, EventHubName, producerOptions, retryPolicy)); }
public async Task ProducerIsConstructedCorrectly() { var partition = "123"; EventHubRetryPolicy retryPolicy = Mock.Of <EventHubRetryPolicy>(); var mock = new ObservableSenderMock(new ClientMock(), partition); var producer = new TrackOneEventHubProducer(_ => mock, retryPolicy); // Invoke an operation to force the producer to be lazily instantiated. Otherwise, // construction does not happen. await producer.SendAsync(new[] { new EventData(new byte[] { 0x12, 0x22 }) }, new SendOptions(), default); Assert.That(mock.ConstructedWithPartition, Is.EqualTo(partition)); EventHubRetryPolicy producerRetry = GetRetryPolicy(producer); Assert.That(producerRetry, Is.SameAs(retryPolicy), "The producer retry instance should match."); }
/// <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, EventHubRetryPolicy 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.SafeClose()); }
/// <summary> /// Initializes a new instance of the <see cref="TrackOneEventHubClient"/> class. /// </summary> /// /// <param name="host">The fully qualified host name for the Event Hubs namespace. 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 connect the client to.</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="clientOptions">A set of options to apply when configuring the client.</param> /// <param name="defaultRetryPolicy">The default retry policy to use if no retry options were specified in the <paramref name="clientOptions" />.</param> /// <param name="eventHubClientFactory">A delegate that can be used for creation of the <see cref="TrackOne.EventHubClient" /> to which operations are delegated to.</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 TrackOneEventHubClient(string host, string eventHubName, TokenCredential credential, EventHubClientOptions clientOptions, EventHubRetryPolicy defaultRetryPolicy, Func <string, string, TokenCredential, EventHubClientOptions, Func <EventHubRetryPolicy>, TrackOne.EventHubClient> eventHubClientFactory) { Argument.AssertNotNullOrEmpty(host, nameof(host)); Argument.AssertNotNullOrEmpty(eventHubName, nameof(eventHubName)); Argument.AssertNotNull(credential, nameof(credential)); Argument.AssertNotNull(clientOptions, nameof(clientOptions)); Argument.AssertNotNull(defaultRetryPolicy, nameof(defaultRetryPolicy)); EventHubName = eventHubName; _retryPolicy = defaultRetryPolicy; _trackOneClient = new Lazy <TrackOne.EventHubClient>(() => eventHubClientFactory(host, eventHubName, credential, clientOptions, () => _retryPolicy), LazyThreadSafetyMode.ExecutionAndPublication); }
/// <summary> /// Initializes a new instance of the <see cref="AmqpEventHubClient"/> class. /// </summary> /// /// <param name="host">The fully qualified host name for the Event Hubs namespace. 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 connect the client to.</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="clientOptions">A set of options to apply when configuring the client.</param> /// <param name="defaultRetryPolicy">The default retry policy to use if no retry options were specified in the <paramref name="clientOptions" />.</param> /// <param name="connectionScope">The optional scope to use for AMQP connection management. If <c>null</c>, a new scope will be created.</param> /// <param name="messageConverter">The optional converter to use for transforming AMQP message-related types. If <c>null</c>, a new converter will be created.</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> /// protected AmqpEventHubClient(string host, string eventHubName, TokenCredential credential, EventHubClientOptions clientOptions, EventHubRetryPolicy defaultRetryPolicy, AmqpConnectionScope connectionScope, AmqpMessageConverter messageConverter) { Argument.AssertNotNullOrEmpty(host, nameof(host)); Argument.AssertNotNullOrEmpty(eventHubName, nameof(eventHubName)); Argument.AssertNotNull(credential, nameof(credential)); Argument.AssertNotNull(clientOptions, nameof(clientOptions)); Argument.AssertNotNull(defaultRetryPolicy, nameof(defaultRetryPolicy)); try { EventHubsEventSource.Log.EventHubClientCreateStart(host, eventHubName); EventHubName = eventHubName; Credential = credential; MessageConverter = messageConverter ?? new AmqpMessageConverter(); if (connectionScope == null) { var endpointBuilder = new UriBuilder { Scheme = clientOptions.TransportType.GetUriScheme(), Host = host }; connectionScope = new AmqpConnectionScope(endpointBuilder.Uri, eventHubName, credential, clientOptions.TransportType, clientOptions.Proxy); } ConnectionScope = connectionScope; ManagementLink = new FaultTolerantAmqpObject <RequestResponseAmqpLink>(timeout => ConnectionScope.OpenManagementLinkAsync(timeout, CancellationToken.None), link => link.SafeClose()); _retryPolicy = defaultRetryPolicy; _tryTimeout = _retryPolicy.CalculateTryTimeout(0); } finally { EventHubsEventSource.Log.EventHubClientCreateComplete(host, eventHubName); } }
/// <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="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="consumerOptions">The set of options to apply when creating the consumer.</param> /// <param name="defaultRetryPolicy">The default retry policy to use if no retry options were specified in the <paramref name="consumerOptions" />.</param> /// /// <returns>An Event Hub consumer configured in the requested manner.</returns> /// public override EventHubConsumer CreateConsumer(string consumerGroup, string partitionId, EventPosition eventPosition, EventHubConsumerOptions consumerOptions, EventHubRetryPolicy defaultRetryPolicy) { Argument.AssertNotClosed(_closed, nameof(AmqpEventHubClient)); EventHubRetryPolicy retryPolicy = defaultRetryPolicy ?? _retryPolicy; var transportConsumer = new AmqpEventHubConsumer ( EventHubName, consumerGroup, partitionId, eventPosition, consumerOptions, ConnectionScope, MessageConverter, retryPolicy ); return(new EventHubConsumer(transportConsumer, EventHubName, consumerGroup, partitionId, eventPosition, consumerOptions, retryPolicy)); }
/// <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, EventHubRetryPolicy 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 = Stopwatch.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 AquireAccessTokenAsync(cancellationToken).ConfigureAwait(false); using AmqpMessage request = MessageConverter.CreatePartitionPropertiesRequest(EventHubName, partitionId, token); cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>(); link = await ManagementLink.GetOrCreateAsync(UseMinimum(ConnectionScope.SessionTimeout, tryTimeout.CalculateRemaining(stopWatch.Elapsed))).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>(); // Send the request and wait for the response. using AmqpMessage response = await link.RequestAsync(request, tryTimeout.CalculateRemaining(stopWatch.Elapsed)).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>(); stopWatch.Stop(); // Process the response. AmqpError.ThrowIfErrorResponse(response, EventHubName); return(MessageConverter.CreatePartitionPropertiesFromResponse(response)); } 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) && (!ConnectionScope.IsDisposed) && (!cancellationToken.IsCancellationRequested)) { EventHubsEventSource.Log.GetPartitionPropertiesError(EventHubName, partitionId, ex.Message); await Task.Delay(retryDelay.Value, cancellationToken).ConfigureAwait(false); tryTimeout = retryPolicy.CalculateTryTimeout(failedAttemptCount); stopWatch.Reset(); } 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 { stopWatch.Stop(); EventHubsEventSource.Log.GetPartitionPropertiesComplete(EventHubName, partitionId); } }
/// <summary> /// Updates the active retry policy for the client. /// </summary> /// /// <param name="newRetryPolicy">The retry policy to set as active.</param> /// public abstract void UpdateRetryPolicy(EventHubRetryPolicy newRetryPolicy);