예제 #1
0
        internal static async Task <AmqpResponseMessage> ExecuteRequestResponseAsync(
            AmqpConnectionScope connectionScope,
            FaultTolerantAmqpObject <RequestResponseAmqpLink> managementLink,
            AmqpRequestMessage amqpRequestMessage,
            string transactionGroup,
            TimeSpan timeout)
        {
            AmqpMessage amqpMessage = amqpRequestMessage.AmqpMessage;

            ArraySegment <byte> transactionId = AmqpConstants.NullBinary;
            var ambientTransaction            = Transaction.Current;

            if (ambientTransaction != null)
            {
                transactionId = await AmqpTransactionManager.Instance.EnlistAsync(
                    ambientTransaction,
                    connectionScope,
                    transactionGroup,
                    timeout)
                                .ConfigureAwait(false);
            }

            if (!managementLink.TryGetOpenedObject(out var requestResponseAmqpLink))
            {
                // MessagingEventSource.Log.CreatingNewLink(this.ClientId, this.isSessionReceiver, this.SessionIdInternal, true, this.LinkException);
                requestResponseAmqpLink = await managementLink.GetOrCreateAsync(timeout).ConfigureAwait(false);
            }

            var responseAmqpMessage = await Task.Factory.FromAsync(
                (c, s) => requestResponseAmqpLink.BeginRequest(amqpMessage, transactionId, timeout, c, s),
                (a) => requestResponseAmqpLink.EndRequest(a),
                null).ConfigureAwait(false);

            return(AmqpResponseMessage.CreateResponse(responseAmqpMessage));
        }
        /// <summary>
        /// Adds a rule to the current subscription to filter the messages reaching from topic to the subscription.
        /// </summary>
        ///
        /// <param name="description">The rule description that provides the rule to add.</param>
        /// <param name="timeout">The per-try timeout specified in the RetryOptions.</param>
        ///
        /// <returns>A task instance that represents the asynchronous add rule operation.</returns>
        private async Task AddRuleInternalAsync(
            RuleProperties description,
            TimeSpan timeout)
        {
            // Create an AmqpRequest Message to add rule
            var amqpRequestMessage = AmqpRequestMessage.CreateRequest(
                ManagementConstants.Operations.AddRuleOperation,
                timeout,
                null);

            amqpRequestMessage.Map[ManagementConstants.Properties.RuleName]        = description.Name;
            amqpRequestMessage.Map[ManagementConstants.Properties.RuleDescription] = AmqpMessageConverter.GetRuleDescriptionMap(description);

            AmqpResponseMessage response = await ManagementUtilities.ExecuteRequestResponseAsync(
                _connectionScope,
                _managementLink,
                amqpRequestMessage,
                null,
                timeout).ConfigureAwait(false);

            if (response.StatusCode != AmqpResponseStatusCode.OK)
            {
                throw response.ToMessagingContractException();
            }
        }
예제 #3
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="amqpRequestMessage"></param>
        /// <param name="timeout"></param>
        /// <returns></returns>
        internal async Task <AmqpResponseMessage> ExecuteRequestResponseAsync(
            AmqpRequestMessage amqpRequestMessage,
            TimeSpan timeout)
        {
            var amqpMessage = amqpRequestMessage.AmqpMessage;

            ArraySegment <byte> transactionId = AmqpConstants.NullBinary;

            //var ambientTransaction = Transaction.Current;
            //if (ambientTransaction != null)
            //{
            //    transactionId = await AmqpTransactionManager.Instance.EnlistAsync(ambientTransaction, this.ServiceBusConnection).ConfigureAwait(false);
            //}

            if (!ManagementLink.TryGetOpenedObject(out var requestResponseAmqpLink))
            {
                // MessagingEventSource.Log.CreatingNewLink(this.ClientId, this.isSessionReceiver, this.SessionIdInternal, true, this.LinkException);
                requestResponseAmqpLink = await ManagementLink.GetOrCreateAsync(timeout).ConfigureAwait(false);
            }

            var responseAmqpMessage = await Task.Factory.FromAsync(
                (c, s) => requestResponseAmqpLink.BeginRequest(amqpMessage, transactionId, timeout, c, s),
                (a) => requestResponseAmqpLink.EndRequest(a),
                this).ConfigureAwait(false);

            return(AmqpResponseMessage.CreateResponse(responseAmqpMessage));
        }
예제 #4
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="sequenceNumber"></param>
        /// <param name="timeout"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        internal async Task CancelScheduledMessageInternalAsync(
            long sequenceNumber,
            TimeSpan timeout,
            CancellationToken cancellationToken = default)
        {
            var stopWatch = Stopwatch.StartNew();

            var request = AmqpRequestMessage.CreateRequest(
                ManagementConstants.Operations.CancelScheduledMessageOperation,
                timeout,
                null);

            if (_sendLink.TryGetOpenedObject(out SendingAmqpLink sendLink))
            {
                request.AmqpMessage.ApplicationProperties.Map[ManagementConstants.Request.AssociatedLinkName] = sendLink.Name;
            }

            request.Map[ManagementConstants.Properties.SequenceNumbers] = new[] { sequenceNumber };

            AmqpResponseMessage amqpResponseMessage = await ManagementUtilities.ExecuteRequestResponseAsync(
                _connectionScope,
                _managementLink,
                request,
                timeout).ConfigureAwait(false);

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

            if (amqpResponseMessage.StatusCode != AmqpResponseStatusCode.OK)
            {
                throw amqpResponseMessage.ToMessagingContractException();
            }
        }
예제 #5
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="sequenceNumbers"></param>
        /// <param name="timeout"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        internal async Task CancelScheduledMessageInternalAsync(
            long[] sequenceNumbers,
            TimeSpan timeout,
            CancellationToken cancellationToken = default)
        {
            var sendLink = default(SendingAmqpLink);

            try
            {
                var request = AmqpRequestMessage.CreateRequest(
                    ManagementConstants.Operations.CancelScheduledMessageOperation,
                    timeout,
                    null);

                if (_sendLink.TryGetOpenedObject(out sendLink))
                {
                    request.AmqpMessage.ApplicationProperties.Map[ManagementConstants.Request.AssociatedLinkName] = sendLink.Name;
                }

                request.Map[ManagementConstants.Properties.SequenceNumbers] = sequenceNumbers;

                AmqpResponseMessage amqpResponseMessage = await ManagementUtilities.ExecuteRequestResponseAsync(
                    _connectionScope,
                    _managementLink,
                    request,
                    _transactionGroup,
                    timeout).ConfigureAwait(false);

                cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>();

                if (amqpResponseMessage.StatusCode != AmqpResponseStatusCode.OK)
                {
                    throw amqpResponseMessage.ToMessagingContractException();
                }
            }
            catch (Exception exception)
            {
                ExceptionDispatchInfo.Capture(AmqpExceptionHelper.TranslateException(
                                                  exception,
                                                  sendLink?.GetTrackingId(),
                                                  null,
                                                  HasLinkCommunicationError(sendLink)))
                .Throw();

                throw; // will never be reached
            }
        }
예제 #6
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="sequenceNumber"></param>
        /// <param name="retryPolicy"></param>
        /// <param name="receiveLinkName"></param>
        /// <param name="timeout"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        internal async Task CancelScheduledMessageInternal(
            long sequenceNumber,
            ServiceBusRetryPolicy retryPolicy,
            string receiveLinkName,
            TimeSpan timeout,
            CancellationToken cancellationToken = default)
        {
            var stopWatch = Stopwatch.StartNew();

            var request = AmqpRequestMessage.CreateRequest(
                ManagementConstants.Operations.CancelScheduledMessageOperation,
                timeout,
                null);

            if (receiveLinkName != null)
            {
                request.AmqpMessage.ApplicationProperties.Map[ManagementConstants.Request.AssociatedLinkName] = receiveLinkName;
            }

            request.Map[ManagementConstants.Properties.SequenceNumbers] = new[] { sequenceNumber };

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

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

            cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>();
            stopWatch.Stop();
            AmqpResponseMessage amqpResponseMessage = AmqpResponseMessage.CreateResponse(response);


            if (amqpResponseMessage.StatusCode != AmqpResponseStatusCode.OK)
            {
                throw new Exception();
                //throw response.ToMessagingContractException();
            }
            return;
        }
예제 #7
0
        /// <summary>
        /// Removes the rule on the subscription identified by <paramref name="ruleName" />.
        /// </summary>
        ///
        /// <param name="ruleName">Name of the rule</param>
        /// <param name="timeout">The per-try timeout specified in the RetryOptions.</param>
        ///
        /// <returns>A task instance that represents the asynchronous remove rule operation.</returns>
        private async Task RemoveRuleInternalAsync(
            string ruleName,
            TimeSpan timeout)
        {
            // Create an AmqpRequest Message to remove rule
            var amqpRequestMessage = AmqpRequestMessage.CreateRequest(
                ManagementConstants.Operations.RemoveRuleOperation,
                timeout,
                null);

            amqpRequestMessage.Map[ManagementConstants.Properties.RuleName] = ruleName;

            AmqpResponseMessage response = await ManagementUtilities.ExecuteRequestResponseAsync(
                _connectionScope,
                _managementLink,
                amqpRequestMessage,
                timeout).ConfigureAwait(false);

            if (response.StatusCode != AmqpResponseStatusCode.OK)
            {
                throw response.ToMessagingContractException();
            }
        }
예제 #8
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="message"></param>
        /// <param name="timeout"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        internal async Task <long> ScheduleMessageInternalAsync(
            ServiceBusMessage message,
            TimeSpan timeout,
            CancellationToken cancellationToken = default)
        {
            var stopWatch = Stopwatch.StartNew();

            using (AmqpMessage amqpMessage = AmqpMessageConverter.SBMessageToAmqpMessage(message))
            {
                var request = AmqpRequestMessage.CreateRequest(
                    ManagementConstants.Operations.ScheduleMessageOperation,
                    timeout,
                    null);

                if (_sendLink.TryGetOpenedObject(out SendingAmqpLink sendLink))
                {
                    request.AmqpMessage.ApplicationProperties.Map[ManagementConstants.Request.AssociatedLinkName] = sendLink.Name;
                }

                ArraySegment <byte>[] payload = amqpMessage.GetPayload();
                var buffer = new BufferListStream(payload);
                ArraySegment <byte> value = buffer.ReadBytes((int)buffer.Length);

                var entry = new AmqpMap();
                {
                    entry[ManagementConstants.Properties.Message]   = value;
                    entry[ManagementConstants.Properties.MessageId] = message.MessageId;

                    if (!string.IsNullOrWhiteSpace(message.SessionId))
                    {
                        entry[ManagementConstants.Properties.SessionId] = message.SessionId;
                    }

                    if (!string.IsNullOrWhiteSpace(message.PartitionKey))
                    {
                        entry[ManagementConstants.Properties.PartitionKey] = message.PartitionKey;
                    }

                    if (!string.IsNullOrWhiteSpace(message.ViaPartitionKey))
                    {
                        entry[ManagementConstants.Properties.ViaPartitionKey] = message.ViaPartitionKey;
                    }
                }

                request.Map[ManagementConstants.Properties.Messages] = new List <AmqpMap> {
                    entry
                };

                RequestResponseAmqpLink mgmtLink = await _managementLink.GetOrCreateAsync(
                    UseMinimum(_connectionScope.SessionTimeout,
                               timeout.CalculateRemaining(stopWatch.Elapsed)))
                                                   .ConfigureAwait(false);

                using AmqpMessage response = await mgmtLink.RequestAsync(
                          request.AmqpMessage,
                          timeout.CalculateRemaining(stopWatch.Elapsed))
                                             .ConfigureAwait(false);

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

                AmqpResponseMessage amqpResponseMessage = AmqpResponseMessage.CreateResponse(response);

                if (amqpResponseMessage.StatusCode == AmqpResponseStatusCode.OK)
                {
                    var sequenceNumbers = amqpResponseMessage.GetValue <long[]>(ManagementConstants.Properties.SequenceNumbers);
                    if (sequenceNumbers == null || sequenceNumbers.Length < 1)
                    {
                        throw new ServiceBusException(true, "Could not schedule message successfully.");
                    }

                    return(sequenceNumbers[0]);
                }
                else
                {
                    throw amqpResponseMessage.ToMessagingContractException();
                }
            }
        }
예제 #9
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="message"></param>
        /// <param name="timeout"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        internal async Task <long> ScheduleMessageInternalAsync(
            ServiceBusMessage message,
            TimeSpan timeout,
            CancellationToken cancellationToken = default)
        {
            var sendLink = default(SendingAmqpLink);

            try
            {
                using (AmqpMessage amqpMessage = AmqpMessageConverter.SBMessageToAmqpMessage(message))
                {
                    var request = AmqpRequestMessage.CreateRequest(
                        ManagementConstants.Operations.ScheduleMessageOperation,
                        timeout,
                        null);

                    if (_sendLink.TryGetOpenedObject(out sendLink))
                    {
                        request.AmqpMessage.ApplicationProperties.Map[ManagementConstants.Request.AssociatedLinkName] = sendLink.Name;
                    }

                    ArraySegment <byte>[] payload = amqpMessage.GetPayload();
                    var buffer = new BufferListStream(payload);
                    ArraySegment <byte> value = buffer.ReadBytes((int)buffer.Length);

                    var entry = new AmqpMap();
                    {
                        entry[ManagementConstants.Properties.Message]   = value;
                        entry[ManagementConstants.Properties.MessageId] = message.MessageId;

                        if (!string.IsNullOrWhiteSpace(message.SessionId))
                        {
                            entry[ManagementConstants.Properties.SessionId] = message.SessionId;
                        }

                        if (!string.IsNullOrWhiteSpace(message.PartitionKey))
                        {
                            entry[ManagementConstants.Properties.PartitionKey] = message.PartitionKey;
                        }

                        if (!string.IsNullOrWhiteSpace(message.ViaPartitionKey))
                        {
                            entry[ManagementConstants.Properties.ViaPartitionKey] = message.ViaPartitionKey;
                        }
                    }

                    request.Map[ManagementConstants.Properties.Messages] = new List <AmqpMap> {
                        entry
                    };


                    AmqpResponseMessage amqpResponseMessage = await ManagementUtilities.ExecuteRequestResponseAsync(
                        _connectionScope,
                        _managementLink,
                        request,
                        timeout).ConfigureAwait(false);

                    cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>();

                    if (amqpResponseMessage.StatusCode == AmqpResponseStatusCode.OK)
                    {
                        var sequenceNumbers = amqpResponseMessage.GetValue <long[]>(ManagementConstants.Properties.SequenceNumbers);
                        if (sequenceNumbers == null || sequenceNumbers.Length < 1)
                        {
                            throw new ServiceBusException(true, "Could not schedule message successfully.");
                        }

                        return(sequenceNumbers[0]);
                    }
                    else
                    {
                        throw amqpResponseMessage.ToMessagingContractException();
                    }
                }
            }
            catch (Exception exception)
            {
                ExceptionDispatchInfo.Capture(AmqpExceptionHelper.TranslateException(
                                                  exception,
                                                  sendLink?.GetTrackingId(),
                                                  null,
                                                  HasLinkCommunicationError(sendLink)))
                .Throw();

                throw; // will never be reached
            }
        }
예제 #10
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();
        }
예제 #11
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="message"></param>
        /// <param name="retryPolicy"></param>
        /// <param name="receiveLinkName"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public override async Task <long> ScheduleMessageAsync(
            ServiceBusMessage message,
            ServiceBusRetryPolicy retryPolicy,
            string receiveLinkName = null,
            CancellationToken cancellationToken = default)
        {
            var failedAttemptCount = 0;
            var stopWatch          = Stopwatch.StartNew();

            try
            {
                TimeSpan tryTimeout = retryPolicy.CalculateTryTimeout(0);
                while (!cancellationToken.IsCancellationRequested)
                {
                    try
                    {
                        using (AmqpMessage amqpMessage = AmqpMessageConverter.SBMessageToAmqpMessage(message))
                        {
                            var request = AmqpRequestMessage.CreateRequest(
                                ManagementConstants.Operations.ScheduleMessageOperation,
                                tryTimeout,
                                null);

                            if (receiveLinkName != null)
                            {
                                request.AmqpMessage.ApplicationProperties.Map[ManagementConstants.Request.AssociatedLinkName] = receiveLinkName;
                            }

                            ArraySegment <byte>[] payload = amqpMessage.GetPayload();
                            var buffer = new BufferListStream(payload);
                            ArraySegment <byte> value = buffer.ReadBytes((int)buffer.Length);

                            var entry = new AmqpMap();
                            {
                                entry[ManagementConstants.Properties.Message]   = value;
                                entry[ManagementConstants.Properties.MessageId] = message.MessageId;

                                if (!string.IsNullOrWhiteSpace(message.SessionId))
                                {
                                    entry[ManagementConstants.Properties.SessionId] = message.SessionId;
                                }

                                if (!string.IsNullOrWhiteSpace(message.PartitionKey))
                                {
                                    entry[ManagementConstants.Properties.PartitionKey] = message.PartitionKey;
                                }

                                if (!string.IsNullOrWhiteSpace(message.ViaPartitionKey))
                                {
                                    entry[ManagementConstants.Properties.ViaPartitionKey] = message.ViaPartitionKey;
                                }
                            }

                            request.Map[ManagementConstants.Properties.Messages] = new List <AmqpMap> {
                                entry
                            };


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

                            using AmqpMessage response = await link.RequestAsync(
                                      request.AmqpMessage,
                                      tryTimeout.CalculateRemaining(stopWatch.Elapsed))
                                                         .ConfigureAwait(false);

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

                            AmqpResponseMessage amqpResponseMessage = AmqpResponseMessage.CreateResponse(response);

                            if (amqpResponseMessage.StatusCode == AmqpResponseStatusCode.OK)
                            {
                                var sequenceNumbers = amqpResponseMessage.GetValue <long[]>(ManagementConstants.Properties.SequenceNumbers);
                                if (sequenceNumbers == null || sequenceNumbers.Length < 1)
                                {
                                    throw new ServiceBusException(true, "Could not schedule message successfully.");
                                }

                                return(sequenceNumbers[0]);
                            }
                            else
                            {
                                throw new Exception();

                                //throw response.ToMessagingContractException();
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        // Determine if there should be a retry for the next attempt; if so enforce the delay but do not quit the loop.
                        // Otherwise, mark the exception as active and break out of the loop.

                        ++failedAttemptCount;
                        TimeSpan?retryDelay = retryPolicy.CalculateRetryDelay(ex, failedAttemptCount);

                        if (retryDelay.HasValue && !ConnectionScope.IsDisposed && !cancellationToken.IsCancellationRequested)
                        {
                            ServiceBusEventSource.Log.ScheduleMessageError(EntityName, ex.Message);
                            await Task.Delay(retryDelay.Value, cancellationToken).ConfigureAwait(false);

                            tryTimeout = retryPolicy.CalculateTryTimeout(failedAttemptCount);
                            stopWatch.Reset();
                        }
                    }
                }
                // 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.ScheduleMessageError(EntityName, ex.Message);
                throw;
            }
            finally
            {
                stopWatch.Stop();
                ServiceBusEventSource.Log.ScheduleMessageComplete(EntityName);
            }
        }
예제 #12
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="sequenceNumber"></param>
        /// <param name="retryPolicy"></param>
        /// <param name="receiveLinkName"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public override async Task CancelScheduledMessageAsync(
            long sequenceNumber,
            ServiceBusRetryPolicy retryPolicy,
            string receiveLinkName = null,
            CancellationToken cancellationToken = default)
        {
            var failedAttemptCount = 0;
            var stopWatch          = Stopwatch.StartNew();

            try
            {
                var tryTimeout = retryPolicy.CalculateTryTimeout(0);

                while (!cancellationToken.IsCancellationRequested)
                {
                    try
                    {
                        var request = AmqpRequestMessage.CreateRequest(
                            ManagementConstants.Operations.CancelScheduledMessageOperation,
                            tryTimeout,
                            null);

                        if (receiveLinkName != null)
                        {
                            request.AmqpMessage.ApplicationProperties.Map[ManagementConstants.Request.AssociatedLinkName] = receiveLinkName;
                        }

                        request.Map[ManagementConstants.Properties.SequenceNumbers] = new[] { sequenceNumber };

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

                        using AmqpMessage response = await link.RequestAsync(
                                  request.AmqpMessage,
                                  tryTimeout.CalculateRemaining(stopWatch.Elapsed))
                                                     .ConfigureAwait(false);

                        cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>();
                        stopWatch.Stop();
                        AmqpResponseMessage amqpResponseMessage = AmqpResponseMessage.CreateResponse(response);


                        if (amqpResponseMessage.StatusCode != AmqpResponseStatusCode.OK)
                        {
                            throw new Exception();
                            //throw response.ToMessagingContractException();
                        }
                        return;
                    }

                    catch (Exception ex)
                    {
                        // Determine if there should be a retry for the next attempt; if so enforce the delay but do not quit the loop.
                        // Otherwise, mark the exception as active and break out of the loop.

                        ++failedAttemptCount;
                        TimeSpan?retryDelay = retryPolicy.CalculateRetryDelay(ex, failedAttemptCount);

                        if (retryDelay.HasValue && !ConnectionScope.IsDisposed && !cancellationToken.IsCancellationRequested)
                        {
                            ServiceBusEventSource.Log.CancelScheduledMessageError(EntityName, ex.Message);
                            await Task.Delay(retryDelay.Value, cancellationToken).ConfigureAwait(false);

                            tryTimeout = retryPolicy.CalculateTryTimeout(failedAttemptCount);
                            stopWatch.Reset();
                        }
                        else
                        {
                            throw ex;
                        }
                    }
                }
                // 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.CancelScheduledMessageError(EntityName, ex.Message);
                throw;
            }
            finally
            {
                stopWatch.Stop();
                ServiceBusEventSource.Log.CancelScheduledMessageComplete(EntityName);
            }
        }