/// <summary> /// Attempts to add an event to the batch, ensuring that the size /// of the batch does not exceed its maximum. /// </summary> /// /// <param name="eventData">The event to attempt to add to the batch.</param> /// /// <returns><c>true</c> if the event was added; otherwise, <c>false</c>.</returns> /// public override bool TryAdd(EventData eventData) { Argument.AssertNotNull(eventData, nameof(eventData)); Argument.AssertNotDisposed(_disposed, nameof(EventDataBatch)); AmqpMessage eventMessage = MessageConverter.CreateMessageFromEvent(eventData, Options.PartitionKey); try { // Calculate the size for the event, based on the AMQP message size and accounting for a // bit of reserved overhead size. var size = _sizeBytes + eventMessage.SerializedMessageSize + (eventMessage.SerializedMessageSize <= MaximumBytesSmallMessage ? OverheadBytesSmallMessage : OverheadBytesLargeMessage); if (size > MaximumSizeInBytes) { return(false); } _sizeBytes = size; BatchEvents.Add(eventData); return(true); } finally { eventMessage?.Dispose(); } }
/// <summary> /// Attempts to add an event to the batch, ensuring that the size /// of the batch does not exceed its maximum. /// </summary> /// /// <param name="eventData">The event to attempt to add to the batch.</param> /// /// <returns><c>true</c> if the event was added; otherwise, <c>false</c>.</returns> /// public override bool TryAdd(EventData eventData) { Guard.ArgumentNotNull(nameof(eventData), eventData); GuardDisposed(); var eventMessage = MessageConverter.CreateMessageFromEvent(eventData, Options.PartitionKey); try { // Calculate the size for the event, based on the AMQP message size and accounting for a // bit of reserved overhead size. var size = _sizeBytes + eventMessage.SerializedMessageSize + (eventMessage.SerializedMessageSize <= MaximumBytesSmallMessage ? OverheadBytesSmallMessage : OverheadBytesLargeMessage); if (size > MaximumSizeInBytes) { eventMessage.Dispose(); return(false); } _sizeBytes = size; BatchMessages.Add(eventMessage); return(true); } catch { eventMessage?.Dispose(); throw; } }
/// <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="sendOptions">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> /// public override async Task SendAsync(IReadOnlyCollection <EventData> events, SendEventOptions sendOptions, CancellationToken cancellationToken) { Argument.AssertNotNull(events, nameof(events)); Argument.AssertNotClosed(_closed, nameof(AmqpProducer)); Argument.AssertNotClosed(ConnectionScope.IsDisposed, nameof(EventHubConnection)); var partitionKey = sendOptions?.PartitionKey; var messages = new AmqpMessage[events.Count]; var index = 0; foreach (var eventData in events) { messages[index] = MessageConverter.CreateMessageFromEvent(eventData, partitionKey); ++index; } try { await SendAsync(messages, partitionKey, cancellationToken).ConfigureAwait(false); } finally { foreach (var message in messages) { message.Dispose(); } } }
/// <summary> /// Attempts to add an event to the batch, ensuring that the size /// of the batch does not exceed its maximum. /// </summary> /// /// <param name="eventData">The event to attempt to add to the batch.</param> /// /// <returns><c>true</c> if the event was added; otherwise, <c>false</c>.</returns> /// public override bool TryAdd(EventData eventData) { Argument.AssertNotNull(eventData, nameof(eventData)); Argument.AssertNotDisposed(_disposed, nameof(EventDataBatch)); // Reserve space for producer-owned fields that correspond to special // features, if enabled. if ((ActiveFeatures & TransportProducerFeatures.IdempotentPublishing) != 0) { eventData.PendingPublishSequenceNumber = int.MaxValue; eventData.PendingProducerGroupId = long.MaxValue; eventData.PendingProducerOwnerLevel = short.MaxValue; } try { using var eventMessage = MessageConverter.CreateMessageFromEvent(eventData, Options.PartitionKey); // Calculate the size for the event, based on the AMQP message size and accounting for a // bit of reserved overhead size. var size = _sizeBytes + eventMessage.SerializedMessageSize + (eventMessage.SerializedMessageSize <= MaximumBytesSmallMessage ? OverheadBytesSmallMessage : OverheadBytesLargeMessage); if (size > MaximumSizeInBytes) { return(false); } _sizeBytes = size; BatchEvents.Add(eventData); return(true); } finally { eventData.ClearPublishingState(); } }
/// <summary> /// Represents the batch as a set of the AMQP-specific representations of an event. /// </summary> /// /// <typeparam name="T">The transport-specific event representation being requested.</typeparam> /// /// <returns>The set of events as an enumerable of the requested type.</returns> /// public override IReadOnlyCollection <T> AsReadOnlyCollection <T>() { if (typeof(T) != typeof(AmqpMessage)) { throw new FormatException(string.Format(CultureInfo.CurrentCulture, Resources.UnsupportedTransportEventType, typeof(T).Name)); } // The AMQP messages must be recreated for each transform request to // ensure that the idempotent publishing properties are current and correct. // // This is a safe pattern, because the method is internal and only invoked // during a send operation, during which the batch is locked to prevent // changes or parallel attempts to send. // // Multiple requests to produce the collection would happen if this batch instance // is being published more than once, which is only valid if a call to SendAsync fails // across all retries, making it a fairly rare occurrence. if (_batchMessages != null) { foreach (var message in _batchMessages) { message.Dispose(); } } _batchMessages = new(_backingStore.Count); // Serialize the events in the batch into their AMQP transport format. Because // the batch holds responsibility for disposing these, hold onto the references. foreach (var eventData in _backingStore) { _batchMessages.Add(MessageConverter.CreateMessageFromEvent(eventData)); } return(_batchMessages as IReadOnlyCollection <T>); }