/// <summary> /// Sends an event to the associated Event Hub using a batched approach. If the size of the event exceeds the /// maximum size of a single batch, an exception will be triggered and the send will fail. /// </summary> /// /// <param name="eventData">The event data to send.</param> /// <param name="options">The set of options to consider when sending this batch.</param> /// <param name="cancellationToken">An optional <see cref="CancellationToken"/> instance to signal the request to cancel the operation.</param> /// /// <returns>A task to be resolved on when the operation has completed.</returns> /// /// <seealso cref="SendAsync(EventData, CancellationToken)" /> /// <seealso cref="SendAsync(IEnumerable{EventData}, CancellationToken)" /> /// <seealso cref="SendAsync(IEnumerable{EventData}, SendEventOptions, CancellationToken)" /> /// <seealso cref="SendAsync(EventDataBatch, CancellationToken)" /> /// internal virtual async Task SendAsync(EventData eventData, SendEventOptions options, CancellationToken cancellationToken = default) { Argument.AssertNotNull(eventData, nameof(eventData)); await SendAsync(new[] { eventData }, options, cancellationToken).ConfigureAwait(false); }
/// <summary> /// Sends an event to the associated Event Hub using a batched approach. If the size of the event exceeds the /// maximum size of a single batch, an exception will be triggered and the send will fail. /// </summary> /// /// <param name="eventData">The event data to send.</param> /// <param name="options">The set of options to consider when sending this batch.</param> /// <param name="cancellationToken">An optional <see cref="CancellationToken"/> instance to signal the request to cancel the operation.</param> /// /// <returns>A task to be resolved on when the operation has completed.</returns> /// /// <seealso cref="SendAsync(EventData, CancellationToken)" /> /// <seealso cref="SendAsync(IEnumerable{EventData}, CancellationToken)" /> /// <seealso cref="SendAsync(IEnumerable{EventData}, SendEventOptions, CancellationToken)" /> /// <seealso cref="SendAsync(EventDataBatch, CancellationToken)" /> /// internal virtual Task SendAsync(EventData eventData, SendEventOptions options, CancellationToken cancellationToken = default) { Argument.AssertNotNull(eventData, nameof(eventData)); return(SendAsync(new[] { eventData }, options, cancellationToken)); }
public Task SendAsync(IEnumerable <EventData> eventDataBatch, string partitionKey, CancellationToken cancellationToken) { if (_client == null) { throw new InvalidOperationException("EventHubClient has not been initialized"); } Azure.Messaging.EventHubs.Producer.SendEventOptions sendEventOptions = null; if (!string.IsNullOrEmpty(partitionKey)) { if (!_partitionKeys.TryGetValue(partitionKey, out sendEventOptions)) { sendEventOptions = new Azure.Messaging.EventHubs.Producer.SendEventOptions() { PartitionKey = partitionKey }; _partitionKeys.TryAdd(partitionKey, sendEventOptions); } } if (sendEventOptions != null) { return(_client.SendAsync(eventDataBatch, sendEventOptions, cancellationToken)); } else { return(_client.SendAsync(eventDataBatch, cancellationToken)); } }
/// <summary> /// Sends a set of events to the associated Event Hub using a batched approach. If the size of events exceed the /// maximum size of a single batch, an exception will be triggered and the send will fail. /// </summary> /// /// <param name="events">The set of event data to send.</param> /// <param name="options">The set of options to consider when sending this batch.</param> /// <param name="cancellationToken">An optional <see cref="CancellationToken" /> instance to signal the request to cancel the operation.</param> /// /// <returns>A task to be resolved on when the operation has completed.</returns> /// /// <seealso cref="SendAsync(EventData, CancellationToken)" /> /// <seealso cref="SendAsync(EventData, SendEventOptions, CancellationToken)" /> /// <seealso cref="SendAsync(IEnumerable{EventData}, CancellationToken)" /> /// <seealso cref="SendAsync(EventDataBatch, CancellationToken)" /> /// internal virtual async Task SendAsync(IEnumerable <EventData> events, SendEventOptions options, CancellationToken cancellationToken = default) { options ??= DefaultSendOptions; Argument.AssertNotNull(events, nameof(events)); AssertSinglePartitionReference(options.PartitionId, options.PartitionKey); int attempts = 0; events = (events as IList <EventData>) ?? events.ToList(); InstrumentMessages(events); var diagnosticIdentifiers = new List <string>(); foreach (var eventData in events) { if (EventDataInstrumentation.TryExtractDiagnosticId(eventData, out var identifier)) { diagnosticIdentifiers.Add(identifier); } } using DiagnosticScope scope = CreateDiagnosticScope(diagnosticIdentifiers); var pooledProducer = PartitionProducerPool.GetPooledProducer(options.PartitionId, PartitionProducerLifespan); while (!cancellationToken.IsCancellationRequested) { try { await using var _ = pooledProducer.ConfigureAwait(false); await pooledProducer.TransportProducer.SendAsync(events, options, cancellationToken).ConfigureAwait(false); return; } catch (EventHubsException eventHubException) when(eventHubException.Reason == EventHubsException.FailureReason.ClientClosed && ShouldRecreateProducer(pooledProducer.TransportProducer, options.PartitionId)) { if (++attempts >= MaximumCreateProducerAttempts) { scope.Failed(eventHubException); throw; } pooledProducer = PartitionProducerPool.GetPooledProducer(options.PartitionId, PartitionProducerLifespan); } catch (Exception ex) { scope.Failed(ex); throw; } } throw new TaskCanceledException(); }
/// <summary> /// Initializes a new instance of the <see cref="EventDataBatch"/> class. /// </summary> /// /// <param name="transportBatch">The transport-specific batch responsible for performing the batch operations.</param> /// <param name="sendOptions">The set of options that should be used when publishing the batch.</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> /// internal EventDataBatch(TransportEventBatch transportBatch, SendEventOptions sendOptions) { Argument.AssertNotNull(transportBatch, nameof(transportBatch)); Argument.AssertNotNull(sendOptions, nameof(sendOptions)); InnerBatch = transportBatch; SendOptions = sendOptions; }
/// <summary> /// Sends a set of events to the associated Event Hub using a batched approach. If the size of events exceed the /// maximum size of a single batch, an exception will be triggered and the send will fail. /// </summary> /// /// <param name="events">The set of event data to send.</param> /// <param name="options">The set of options to consider when sending this batch.</param> /// <param name="cancellationToken">An optional <see cref="CancellationToken"/> instance to signal the request to cancel the operation.</param> /// /// <returns>A task to be resolved on when the operation has completed.</returns> /// /// <seealso cref="SendAsync(EventData, CancellationToken)" /> /// <seealso cref="SendAsync(EventData, SendEventOptions, CancellationToken)" /> /// <seealso cref="SendAsync(IEnumerable{EventData}, CancellationToken)" /> /// <seealso cref="SendAsync(EventDataBatch, CancellationToken)" /> /// internal virtual async Task SendAsync(IEnumerable <EventData> events, SendEventOptions options, CancellationToken cancellationToken = default) { options ??= DefaultSendOptions; Argument.AssertNotNull(events, nameof(events)); AssertSinglePartitionReference(options.PartitionId, options.PartitionKey); // Determine the transport producer to delegate the send operation to. Because sending to a specific // partition requires a dedicated client, use (or create) that client if a partition was specified. Otherwise // the default gateway producer can be used to request automatic routing from the Event Hubs service gateway. TransportProducer activeProducer; if (string.IsNullOrEmpty(options.PartitionId)) { activeProducer = EventHubProducer; } else { // This assertion is intended as an additional check, not as a guarantee. There still exists a benign // race condition where a transport producer may be created after the client has been closed; in this case // the transport producer will be force-closed with the associated connection or, worst case, will close once // its idle timeout period elapses. Argument.AssertNotClosed(IsClosed, nameof(EventHubProducerClient)); activeProducer = PartitionProducers.GetOrAdd(options.PartitionId, id => Connection.CreateTransportProducer(id, RetryPolicy)); } events = (events as IList <EventData>) ?? events.ToList(); InstrumentMessages(events); var diagnosticIdentifiers = new List <string>(); foreach (var eventData in events) { if (EventDataInstrumentation.TryExtractDiagnosticId(eventData, out var identifier)) { diagnosticIdentifiers.Add(identifier); } } using DiagnosticScope scope = CreateDiagnosticScope(diagnosticIdentifiers); try { await activeProducer.SendAsync(events, options, cancellationToken).ConfigureAwait(false); } catch (Exception ex) { scope.Failed(ex); throw; } }
/// <summary> /// Initializes a new instance of the <see cref="EventDataBatch"/> class. /// </summary> /// /// <param name="transportBatch">The transport-specific batch responsible for performing the batch operations.</param> /// <param name="fullyQualifiedNamespace">The fully qualified Event Hubs namespace to use for instrumentation.</param> /// <param name="eventHubName">The name of the specific Event Hub to associate the events with during instrumentation.</param> /// <param name="sendOptions">The set of options that should be used when publishing the batch.</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> /// internal EventDataBatch(TransportEventBatch transportBatch, string fullyQualifiedNamespace, string eventHubName, SendEventOptions sendOptions) { Argument.AssertNotNull(transportBatch, nameof(transportBatch)); Argument.AssertNotNullOrEmpty(fullyQualifiedNamespace, nameof(fullyQualifiedNamespace)); Argument.AssertNotNullOrEmpty(eventHubName, nameof(eventHubName)); Argument.AssertNotNull(sendOptions, nameof(sendOptions)); InnerBatch = transportBatch; FullyQualifiedNamespace = fullyQualifiedNamespace; EventHubName = eventHubName; SendOptions = sendOptions; }