/// <summary> /// Creates the AMQP link to be used for producer-related operations and ensures /// that the corresponding state for the producer has been updated based on the link /// configuration. /// </summary> /// /// <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 associated with the producer.</param> /// <param name="partitionOptions">The set of options, if any, that should be considered when initializing the producer.</param> /// <param name="timeout">The timeout to apply for creating the link.</param> /// <param name="cancellationToken">The cancellation token to consider when creating the link.</param> /// /// <returns>The AMQP link to use for producer-related operations.</returns> /// /// <remarks> /// This method will modify class-level state, setting those attributes that depend on the AMQP /// link configuration. There exists a benign race condition in doing so, as there may be multiple /// concurrent callers. In this case, the attributes may be set multiple times but the resulting /// value will be the same. /// </remarks> /// protected virtual async Task <SendingAmqpLink> CreateLinkAndEnsureProducerStateAsync(string partitionId, string producerIdentifier, PartitionPublishingOptions partitionOptions, TimeSpan timeout, CancellationToken cancellationToken) { var link = default(SendingAmqpLink); var operationTimeout = RetryPolicy.CalculateTryTimeout(0); try { link = await ConnectionScope.OpenProducerLinkAsync(partitionId, ActiveFeatures, partitionOptions, operationTimeout, timeout, producerIdentifier, cancellationToken).ConfigureAwait(false); if (!MaximumMessageSize.HasValue) { // This delay is necessary to prevent the link from causing issues for subsequent // operations after creating a batch. Without it, operations using the link consistently // timeout. The length of the delay does not appear significant, just the act of introducing // an asynchronous delay. // // For consistency the value used by the legacy Event Hubs client has been brought forward and // used here. await Task.Delay(15, cancellationToken).ConfigureAwait(false); MaximumMessageSize = (long)link.Settings.MaxMessageSize; } if (InitializedPartitionProperties == null) { var producerGroup = link.ExtractSettingPropertyValueOrDefault(AmqpProperty.ProducerGroupId, default(long?)); var ownerLevel = link.ExtractSettingPropertyValueOrDefault(AmqpProperty.ProducerOwnerLevel, default(short?)); var sequence = link.ExtractSettingPropertyValueOrDefault(AmqpProperty.ProducerSequenceNumber, default(int?)); // Once the properties are initialized, clear the starting sequence number to ensure that the current // sequence tracked by the service is used should the link need to be recreated; this avoids the need for // the transport producer to have awareness of the sequence numbers of events being sent. InitializedPartitionProperties = new PartitionPublishingProperties(false, producerGroup, ownerLevel, sequence); partitionOptions.StartingSequenceNumber = null; } } catch (Exception ex) { ExceptionDispatchInfo.Capture(ex.TranslateConnectionCloseDuringLinkCreationException(EventHubName)).Throw(); } return(link); }
/// <summary> /// Creates the AMQP link to be used for producer-related operations and ensures /// that the corresponding state for the producer has been updated based on the link /// configuration. /// </summary> /// /// <param name="partitionId">The identifier of the Event Hub partition to which it is bound; if unbound, <c>null</c>.</param> /// <param name="partitionOptions">The set of options, if any, that should be considered when initializing the producer.</param> /// <param name="timeout">The timeout to apply when creating the link.</param> /// <param name="cancellationToken">The cancellation token to consider when creating the link.</param> /// /// <returns>The AMQP link to use for producer-related operations.</returns> /// /// <remarks> /// This method will modify class-level state, setting those attributes that depend on the AMQP /// link configuration. There exists a benign race condition in doing so, as there may be multiple /// concurrent callers. In this case, the attributes may be set multiple times but the resulting /// value will be the same. /// </remarks> /// protected virtual async Task <SendingAmqpLink> CreateLinkAndEnsureProducerStateAsync(string partitionId, PartitionPublishingOptions partitionOptions, TimeSpan timeout, CancellationToken cancellationToken) { var link = default(SendingAmqpLink); try { link = await ConnectionScope.OpenProducerLinkAsync(partitionId, timeout, cancellationToken).ConfigureAwait(false); if (!MaximumMessageSize.HasValue) { // This delay is necessary to prevent the link from causing issues for subsequent // operations after creating a batch. Without it, operations using the link consistently // timeout. The length of the delay does not appear significant, just the act of introducing // an asynchronous delay. // // For consistency the value used by the legacy Event Hubs client has been brought forward and // used here. await Task.Delay(15, cancellationToken).ConfigureAwait(false); MaximumMessageSize = (long)link.Settings.MaxMessageSize; } if (InitializedPartitionProperties == null) { if ((ActiveFeatures & TransportProducerFeatures.IdempotentPublishing) != 0) { throw new NotImplementedException(nameof(CreateLinkAndEnsureProducerStateAsync)); } else { InitializedPartitionProperties = new PartitionPublishingProperties(false, null, null, null); } } } catch (Exception ex) { ExceptionDispatchInfo.Capture(ex.TranslateConnectionCloseDuringLinkCreationException(EventHubName)).Throw(); } return(link); }