Ejemplo n.º 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>());
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Get the session Id corresponding to this consumer
        /// </summary>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public override async Task <string> GetSessionId(CancellationToken cancellationToken = default)
        {
            if (!_isSessionReceiver)
            {
                return(null);
            }
            ReceivingAmqpLink openedLink = null;
            await _retryPolicy.RunOperation(
                async (timeout) =>
                openedLink = await ReceiveLink.GetOrCreateAsync(timeout).ConfigureAwait(false),
                EntityName,
                ConnectionScope,
                cancellationToken).ConfigureAwait(false);

            var source = (Source)openedLink.Settings.Source;

            source.FilterSet.TryGetValue <string>(AmqpClientConstants.SessionFilterName, out var sessionId);
            return(sessionId);
        }
Ejemplo n.º 3
0
        /// <summary>
        ///   Closes the connection to the transport consumer instance.
        /// </summary>
        ///
        /// <param name="cancellationToken">An optional <see cref="CancellationToken"/> instance to signal the request to cancel the operation.</param>
        ///
        public override async Task CloseAsync(CancellationToken cancellationToken)
        {
            if (_closed)
            {
                return;
            }

            _closed = true;

            var clientId   = GetHashCode().ToString();
            var clientType = GetType();

            try
            {
                ServiceBusEventSource.Log.ClientCloseStart(clientType, EntityName, clientId);
                cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>();

                if (ReceiveLink?.TryGetOpenedObject(out var _) == true)
                {
                    cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>();
                    await ReceiveLink.CloseAsync().ConfigureAwait(false);
                }

                ReceiveLink?.Dispose();
            }
            catch (Exception ex)
            {
                _closed = false;
                ServiceBusEventSource.Log.ClientCloseError(clientType, EntityName, clientId, ex.Message);

                throw;
            }
            finally
            {
                ServiceBusEventSource.Log.ClientCloseComplete(clientType, EntityName, clientId);
            }
        }
Ejemplo n.º 4
0
 internal override async Task <ReceivingAmqpLink> GetOrCreateLinkAsync(TimeSpan timeout)
 {
     return(await ReceiveLink.GetOrCreateAsync(timeout).ConfigureAwait(false));
 }
Ejemplo n.º 5
0
        /// <summary>
        /// Completes a series of <see cref="ServiceBusMessage"/> using a list of lock tokens. This will delete the message from the service.
        /// </summary>
        ///
        /// <param name="lockTokens">An <see cref="IEnumerable{T}"/> containing the lock tokens of the corresponding messages to complete.</param>
        /// <param name="outcome"></param>
        /// <param name="timeout"></param>
        internal override async Task DisposeMessagesAsync(
            IEnumerable <Guid> lockTokens,
            Outcome outcome,
            TimeSpan timeout)
        {
            if (_isSessionReceiver)
            {
                // TODO -  ThrowIfSessionLockLost();
            }

            List <ArraySegment <byte> > deliveryTags = ConvertLockTokensToDeliveryTags(lockTokens);

            ReceivingAmqpLink receiveLink = null;

            try
            {
                ArraySegment <byte> transactionId = AmqpConstants.NullBinary;
                //var ambientTransaction = Transaction.Current;
                //if (ambientTransaction != null)
                //{
                //    transactionId = await AmqpTransactionManager.Instance.EnlistAsync(ambientTransaction, ServiceBusConnection).ConfigureAwait(false);
                //}

                if (!ReceiveLink.TryGetOpenedObject(out receiveLink))
                {
                    receiveLink = await ReceiveLink.GetOrCreateAsync(timeout).ConfigureAwait(false);
                }

                var disposeMessageTasks = new Task <Outcome> [deliveryTags.Count];
                var i = 0;
                foreach (ArraySegment <byte> deliveryTag in deliveryTags)
                {
                    disposeMessageTasks[i++] = Task.Factory.FromAsync(
                        (c, s) => receiveLink.BeginDisposeMessage(deliveryTag, transactionId, outcome, true, timeout, c, s),
                        a => receiveLink.EndDisposeMessage(a),
                        this);
                }

                var outcomes = await Task.WhenAll(disposeMessageTasks).ConfigureAwait(false);

                Error error = null;
                foreach (Outcome item in outcomes)
                {
                    var disposedOutcome = item.DescriptorCode == Rejected.Code && ((error = ((Rejected)item).Error) != null) ? item : null;
                    if (disposedOutcome != null)
                    {
                        if (error.Condition.Equals(AmqpErrorCode.NotFound))
                        {
                            if (_isSessionReceiver)
                            {
                                //  throw new SessionLockLostException(Resources.SessionLockExpiredOnMessageSession);
                            }

                            //   throw new MessageLockLostException(Resources.MessageLockLost);
                        }

                        // throw error.ToMessagingContractException();
                    }
                }
            }
            catch (Exception exception)
            {
                if (exception is OperationCanceledException &&
                    receiveLink != null && receiveLink.State != AmqpObjectState.Opened)
                {
                    // The link state is lost, We need to return a non-retriable error.
                    // MessagingEventSource.Log.LinkStateLost(ClientId, receiveLink.Name, receiveLink.State, isSessionReceiver, exception);
                    if (_isSessionReceiver)
                    {
                        //  throw new SessionLockLostException(Resources.SessionLockExpiredOnMessageSession);
                    }

                    // throw new MessageLockLostException(Resources.MessageLockLost);
                }

                // throw AmqpExceptionHelper.GetClientException(exception);
                throw;
            }
        }
Ejemplo n.º 6
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);
            }
        }