Пример #1
0
        /// <summary>
        ///   Receives a batch of <see cref="ServiceBusMessage" /> from the Service Bus entity partition.
        /// </summary>
        ///
        /// <param name="maximumMessageCount">The maximum number of messages to receive in this batch.</param>
        /// <param name="timeout"></param>
        /// <param name="cancellationToken">An optional <see cref="CancellationToken"/> instance to signal the request to cancel the operation.</param>
        ///
        /// <returns>The batch of <see cref="ServiceBusMessage" /> from the Service Bus entity partition this consumer is associated with.  If no events are present, an empty enumerable is returned.</returns>
        ///
        internal async Task <IEnumerable <ServiceBusMessage> > ReceiveAsyncInternal(
            int maximumMessageCount,
            TimeSpan timeout,
            CancellationToken cancellationToken)
        {
            Argument.AssertNotClosed(_closed, nameof(AmqpConsumer));
            Argument.AssertAtLeast(maximumMessageCount, 1, nameof(maximumMessageCount));

            var link             = default(ReceivingAmqpLink);
            var amqpMessages     = default(IEnumerable <AmqpMessage>);
            var receivedMessages = default(List <ServiceBusMessage>);

            var stopWatch = Stopwatch.StartNew();

            ServiceBusEventSource.Log.MessageReceiveStart(EntityName);

            link = await ReceiveLink.GetOrCreateAsync(UseMinimum(ConnectionScope.SessionTimeout, timeout)).ConfigureAwait(false);

            cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>();

            var messagesReceived = await Task.Factory.FromAsync
                                   (
                (callback, state) => link.BeginReceiveRemoteMessages(maximumMessageCount, TimeSpan.FromMilliseconds(20), timeout, callback, state),
                (asyncResult) => link.EndReceiveMessages(asyncResult, out amqpMessages),
                TaskCreationOptions.RunContinuationsAsynchronously
                                   ).ConfigureAwait(false);

            cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>();

            // If event messages were received, then package them for consumption and
            // return them.

            if ((messagesReceived) && (amqpMessages != null))
            {
                receivedMessages = new List <ServiceBusMessage>();

                foreach (AmqpMessage message in amqpMessages)
                {
                    if (_receiveMode == ReceiveMode.ReceiveAndDelete)
                    {
                        link.DisposeDelivery(message, true, AmqpConstants.AcceptedOutcome);
                    }
                    receivedMessages.Add(AmqpMessageConverter.AmqpMessageToSBMessage(message));
                    // message.Dispose();
                }

                stopWatch.Stop();

                return(receivedMessages);
            }

            stopWatch.Stop();

            // No events were available.
            return(Enumerable.Empty <ServiceBusMessage>());
        }
Пример #2
0
        /// <summary>
        ///   Receives a batch of <see cref="ServiceBusMessage" /> from the Service Bus entity partition.
        /// </summary>
        ///
        /// <param name="maximumMessageCount">The maximum number of messages to receive in this batch.</param>
        /// <param name="maximumWaitTime">The maximum amount of time to wait to build up the requested message count for the batch; if not specified, the per-try timeout specified by the retry policy will be used.</param>
        /// <param name="cancellationToken">An optional <see cref="CancellationToken"/> instance to signal the request to cancel the operation.</param>
        ///
        /// <returns>The batch of <see cref="ServiceBusMessage" /> from the Service Bus entity partition this consumer is associated with.  If no events are present, an empty enumerable is returned.</returns>
        ///
        public override async Task <IEnumerable <ServiceBusMessage> > ReceiveAsync(
            int maximumMessageCount,
            TimeSpan?maximumWaitTime,
            CancellationToken cancellationToken)
        {
            Argument.AssertNotClosed(_closed, nameof(AmqpConsumer));
            Argument.AssertAtLeast(maximumMessageCount, 1, nameof(maximumMessageCount));

            var receivedMessageCount = 0;
            var failedAttemptCount   = 0;
            var tryTimeout           = _retryPolicy.CalculateTryTimeout(0);
            var waitTime             = (maximumWaitTime ?? tryTimeout);
            var link             = default(ReceivingAmqpLink);
            var retryDelay       = default(TimeSpan?);
            var amqpMessages     = default(IEnumerable <AmqpMessage>);
            var receivedMessages = default(List <ServiceBusMessage>);

            var stopWatch = Stopwatch.StartNew();

            try
            {
                while (!cancellationToken.IsCancellationRequested)
                {
                    try
                    {
                        ServiceBusEventSource.Log.MessageReceiveStart(EntityName);

                        link = await ReceiveLink.GetOrCreateAsync(UseMinimum(ConnectionScope.SessionTimeout, tryTimeout)).ConfigureAwait(false);

                        cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>();

                        var messagesReceived = await Task.Factory.FromAsync
                                               (
                            (callback, state) => link.BeginReceiveRemoteMessages(maximumMessageCount, TimeSpan.FromMilliseconds(20), waitTime, callback, state),
                            (asyncResult) => link.EndReceiveMessages(asyncResult, out amqpMessages),
                            TaskCreationOptions.RunContinuationsAsynchronously
                                               ).ConfigureAwait(false);

                        cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>();

                        // If event messages were received, then package them for consumption and
                        // return them.

                        if ((messagesReceived) && (amqpMessages != null))
                        {
                            receivedMessages ??= new List <ServiceBusMessage>();

                            foreach (AmqpMessage message in amqpMessages)
                            {
                                //link.DisposeDelivery(message, true, AmqpConstants.AcceptedOutcome);
                                receivedMessages.Add(AmqpMessageConverter.AmqpMessageToSBMessage(message));
                                message.Dispose();
                            }

                            receivedMessageCount = receivedMessages.Count;
                            return(receivedMessages);
                        }

                        // No events were available.

                        return(Enumerable.Empty <ServiceBusMessage>());
                    }
                    catch (ServiceBusException ex) when(ex.Reason == ServiceBusException.FailureReason.ServiceTimeout)
                    {
                        // Because the timeout specified with the request is intended to be the maximum
                        // amount of time to wait for events, a timeout isn't considered an error condition,
                        // rather a sign that no events were available in the requested period.

                        return(Enumerable.Empty <ServiceBusMessage>());
                    }
                    catch (Exception ex)
                    {
                        Exception activeEx = ex.TranslateServiceException(EntityName);

                        // Determine if there should be a retry for the next attempt; if so enforce the delay but do not quit the loop.
                        // Otherwise, bubble the exception.

                        ++failedAttemptCount;
                        retryDelay = _retryPolicy.CalculateRetryDelay(activeEx, failedAttemptCount);

                        if ((retryDelay.HasValue) && (!ConnectionScope.IsDisposed) && (!cancellationToken.IsCancellationRequested))
                        {
                            ServiceBusEventSource.Log.MessageReceiveError(EntityName, activeEx.Message);
                            await Task.Delay(UseMinimum(retryDelay.Value, waitTime.CalculateRemaining(stopWatch.Elapsed)), cancellationToken).ConfigureAwait(false);

                            tryTimeout = _retryPolicy.CalculateTryTimeout(failedAttemptCount);
                        }
                        else if (ex is AmqpException)
                        {
                            throw activeEx;
                        }
                        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)
            {
                ServiceBusEventSource.Log.MessageReceiveError(EntityName, ex.Message);
                throw;
            }
            finally
            {
                stopWatch.Stop();
                ServiceBusEventSource.Log.MessageReceiveComplete(EntityName, receivedMessageCount);
            }
        }
Пример #3
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="retryPolicy"></param>
        /// <param name="fromSequenceNumber"></param>
        /// <param name="messageCount"></param>
        /// <param name="sessionId"></param>
        /// <param name="receiveLinkName"></param>
        /// <param name="timeout"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        internal async Task <IEnumerable <ServiceBusMessage> > PeekInternal(
            ServiceBusRetryPolicy retryPolicy,
            long?fromSequenceNumber,
            int messageCount,
            string sessionId,
            string receiveLinkName,
            TimeSpan timeout,
            CancellationToken cancellationToken = default)
        {
            var stopWatch = new Stopwatch();

            stopWatch.Start();

            AmqpRequestMessage amqpRequestMessage = AmqpRequestMessage.CreateRequest(
                ManagementConstants.Operations.PeekMessageOperation,
                timeout,
                null);

            await AquireAccessTokenAsync(cancellationToken).ConfigureAwait(false);

            if (receiveLinkName != null)
            {
                // include associated link for service optimization
                amqpRequestMessage.AmqpMessage.ApplicationProperties.Map[ManagementConstants.Request.AssociatedLinkName] = receiveLinkName;
            }

            amqpRequestMessage.Map[ManagementConstants.Properties.FromSequenceNumber] = fromSequenceNumber ?? LastPeekedSequenceNumber + 1;
            amqpRequestMessage.Map[ManagementConstants.Properties.MessageCount]       = messageCount;

            if (!string.IsNullOrWhiteSpace(sessionId))
            {
                amqpRequestMessage.Map[ManagementConstants.Properties.SessionId] = sessionId;
            }

            RequestResponseAmqpLink link = await ManagementLink.GetOrCreateAsync(
                UseMinimum(ConnectionScope.SessionTimeout,
                           timeout.CalculateRemaining(stopWatch.Elapsed)))
                                           .ConfigureAwait(false);

            cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>();

            using AmqpMessage responseAmqpMessage = await link.RequestAsync(
                      amqpRequestMessage.AmqpMessage,
                      timeout.CalculateRemaining(stopWatch.Elapsed))
                                                    .ConfigureAwait(false);

            cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>();

            AmqpResponseMessage amqpResponseMessage = AmqpResponseMessage.CreateResponse(responseAmqpMessage);

            var messages = new List <ServiceBusMessage>();

            //AmqpError.ThrowIfErrorResponse(responseAmqpMessage, EntityName);
            if (amqpResponseMessage.StatusCode == AmqpResponseStatusCode.OK)
            {
                ServiceBusMessage     message     = null;
                IEnumerable <AmqpMap> messageList = amqpResponseMessage.GetListValue <AmqpMap>(ManagementConstants.Properties.Messages);
                foreach (AmqpMap entry in messageList)
                {
                    var payload     = (ArraySegment <byte>)entry[ManagementConstants.Properties.Message];
                    var amqpMessage = AmqpMessage.CreateAmqpStreamMessage(new BufferListStream(new[] { payload }), true);
                    message = AmqpMessageConverter.AmqpMessageToSBMessage(amqpMessage, true);
                    messages.Add(message);
                }

                if (message != null)
                {
                    LastPeekedSequenceNumber = message.SystemProperties.SequenceNumber;
                }
                return(messages);
            }

            if (amqpResponseMessage.StatusCode == AmqpResponseStatusCode.NoContent ||
                (amqpResponseMessage.StatusCode == AmqpResponseStatusCode.NotFound && Equals(AmqpClientConstants.MessageNotFoundError, amqpResponseMessage.GetResponseErrorCondition())))
            {
                return(messages);
            }
            // TODO throw correct exception
            throw new Exception();
        }