예제 #1
0
        /// <summary>
        ///   Sends a set of events to the associated Service Bus entity 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="messages">The set of event data to send.</param>
        /// <param name="cancellationToken">An optional <see cref="CancellationToken"/> instance to signal the request to cancel the operation.</param>
        ///
        public override async Task SendAsync(IEnumerable <ServiceBusMessage> messages,
                                             CancellationToken cancellationToken)
        {
            Argument.AssertNotNull(messages, nameof(messages));
            Argument.AssertNotClosed(_closed, nameof(AmqpSender));

            AmqpMessage messageFactory() => AmqpMessageConverter.BatchSBMessagesAsAmqpMessage(messages);
            await SendAsync(messageFactory, cancellationToken).ConfigureAwait(false);
        }
예제 #2
0
        /// <summary>
        ///   Initializes a new instance of the <see cref="AmqpMessageBatch"/> class.
        /// </summary>
        ///
        /// <param name="options">The set of options to apply to the batch.</param>
        ///
        public AmqpMessageBatch(CreateBatchOptions options)
        {
            Argument.AssertNotNull(options, nameof(options));
            Argument.AssertNotNull(options.MaximumSizeInBytes, nameof(options.MaximumSizeInBytes));

            Options            = options;
            MaximumSizeInBytes = options.MaximumSizeInBytes.Value;

            // Initialize the size by reserving space for the batch envelope.

            using AmqpMessage envelope = AmqpMessageConverter.BatchSBMessagesAsAmqpMessage(Enumerable.Empty <ServiceBusMessage>());
            _sizeBytes = envelope.SerializedMessageSize;
        }
예제 #3
0
        /// <summary>
        ///   Sends a set of messages to the associated Queue/Topic using a batched approach.
        /// </summary>
        ///
        /// <param name="messageBatch">The set of messages to send.</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>
        ///
        public override async Task SendBatchAsync(
            ServiceBusMessageBatch messageBatch,
            CancellationToken cancellationToken)
        {
            AmqpMessage messageFactory() => AmqpMessageConverter.BatchSBMessagesAsAmqpMessage(messageBatch.AsEnumerable <ServiceBusMessage>());

            await _retryPolicy.RunOperation(async (timeout) =>
                                            await SendBatchInternalAsync(
                                                messageFactory,
                                                timeout,
                                                cancellationToken).ConfigureAwait(false),
                                            _connectionScope,
                                            cancellationToken).ConfigureAwait(false);
        }
예제 #4
0
        /// <summary>
        ///   Attempts to add a message to the batch, ensuring that the size
        ///   of the batch does not exceed its maximum.
        /// </summary>
        ///
        /// <param name="message">The message to attempt to add to the batch.</param>
        ///
        /// <returns><c>true</c> if the message was added; otherwise, <c>false</c>.</returns>
        ///
        public override bool TryAddMessage(ServiceBusMessage message)
        {
            Argument.AssertNotNull(message, nameof(message));
            Argument.AssertNotDisposed(_disposed, nameof(ServiceBusMessageBatch));

            AmqpMessage amqpMessage = null;

            try
            {
                if (BatchMessages.Count == 0)
                {
                    // Initialize the size by reserving space for the batch envelope taking into account the properties from the first
                    // message which will be used to populate properties on the batch envelope.
                    amqpMessage = AmqpMessageConverter.BatchSBMessagesAsAmqpMessage(message, forceBatch: true);
                }
                else
                {
                    amqpMessage = AmqpMessageConverter.SBMessageToAmqpMessage(message);
                }

                // Calculate the size for the message, based on the AMQP message size and accounting for a
                // bit of reserved overhead size.

                var size = _sizeBytes
                           + amqpMessage.SerializedMessageSize
                           + (amqpMessage.SerializedMessageSize <= MaximumBytesSmallMessage
                        ? OverheadBytesSmallMessage
                        : OverheadBytesLargeMessage);

                if (size > MaxSizeInBytes)
                {
                    return(false);
                }

                _sizeBytes = size;
                BatchMessages.Add(message);

                return(true);
            }
            finally
            {
                amqpMessage?.Dispose();
            }
        }
예제 #5
0
        /// <summary>
        ///    Sends a set of messages to the associated Queue/Topic using a batched approach.
        /// </summary>
        ///
        /// <param name="messageBatch"></param>
        /// <param name="timeout"></param>
        /// <param name="cancellationToken">An optional <see cref="CancellationToken"/> instance to signal the request to cancel the operation.</param>
        ///
        internal virtual async Task SendBatchInternalAsync(
            ServiceBusMessageBatch messageBatch,
            TimeSpan timeout,
            CancellationToken cancellationToken)
        {
            var stopWatch = Stopwatch.StartNew();

            AmqpMessage messageFactory() => AmqpMessageConverter.BatchSBMessagesAsAmqpMessage(messageBatch.AsEnumerable <ServiceBusMessage>());

            using (AmqpMessage batchMessage = messageFactory())
            {
                //ServiceBusEventSource.Log.SendStart(Entityname, messageHash);

                string messageHash = batchMessage.GetHashCode().ToString();

                SendingAmqpLink link = await _sendLink.GetOrCreateAsync(UseMinimum(_connectionScope.SessionTimeout, timeout)).ConfigureAwait(false);

                // Validate that the message is not too large to send.  This is done after the link is created to ensure
                // that the maximum message size is known, as it is dictated by the service using the link.

                if (batchMessage.SerializedMessageSize > MaximumMessageSize)
                {
                    throw new ServiceBusException(string.Format(Resources1.MessageSizeExceeded, messageHash, batchMessage.SerializedMessageSize, MaximumMessageSize, _entityName), ServiceBusException.FailureReason.MessageSizeExceeded);
                }

                // Attempt to send the message batch.

                var deliveryTag = new ArraySegment <byte>(BitConverter.GetBytes(Interlocked.Increment(ref _deliveryCount)));
                var outcome     = await link.SendMessageAsync(batchMessage, deliveryTag, AmqpConstants.NullBinary, timeout.CalculateRemaining(stopWatch.Elapsed)).ConfigureAwait(false);

                cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>();

                if (outcome.DescriptorCode != Accepted.Code)
                {
                    throw AmqpError.CreateExceptionForError((outcome as Rejected)?.Error, _entityName);
                }

                //ServiceBusEventSource.Log.SendStop(Entityname, messageHash);

                cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>();
                stopWatch.Stop();
            }
        }