private async Task ResubmitMessageAsync(Message message, Microsoft.Azure.ServiceBus.Core.MessageSender sender, int resubmitCount)
        {
            // https://markheath.net/post/defer-processing-azure-service-bus-message
            var clone = message.Clone();

            clone.UserProperties["ResubmitCount"] = resubmitCount + 1;
            clone.ScheduledEnqueueTimeUtc         = DateTime.UtcNow
                                                    .AddMinutes(RetryTemporaryErrorsAfterMinutes)
                                                    .AddSeconds(jitterer.Next(0, 120)); // plus some jitter up to 2 minutes
            await sender.SendAsync(clone);
        }
  public async Task ForwardOrder(
 [ServiceBusTrigger(
      queueName: "%ServiceBusSettings:OrderProcessingQueueName%",  // queueName can be stored in your app Configuration as it is here, or hard coded.
      Connection = "ServiceBusSettings:ConnectionString")]
  Message message,
 MessageReceiver messageReceiver,
 [ServiceBus(
      queueOrTopicName: "%ServiceBusSettings:OrderProcessingQueueName%",
      Connection = "ServiceBusSettings:ConnectionString" )]
  MessageSender messageSender,
 ILogger logger) => await _forwardJob.Run(logger, message, messageReceiver, messageSender);
        public async Task Defer(TimeSpan tryAgainIn)
        {
            // Deferral of a message is implemented per the recommendation given here:
            // https://docs.microsoft.com/en-us/azure/service-bus-messaging/message-deferral#message-deferral-apis
            // We defer the message in Azure Service Bus, effectively hiding it indefinitely.
            // We then send a new "control" message to the same queue that contains the sequence number of the deferred message.
            // The control message is scheduled for delivery at a certain time.
            // The message pump will handle the control message by getting the sequence number and using it to obtain the deferred message.
            var sender = new Microsoft.Azure.ServiceBus.Core.MessageSender(_messageReceiver.ServiceBusConnection,
                                                                           _messageReceiver.Path, _messageReceiver.RetryPolicy);

            var controlMessage = new Message();

            controlMessage.UserProperties.Add(Constants.HeaderKeys.RPDeferredMessageSequenceNumber, _message.SystemProperties.SequenceNumber);
            controlMessage.UserProperties.Add(Constants.HeaderKeys.RPContextId, _settings.ContextId);
            //Copy the tenant Id
            if (_message.UserProperties.TryGetValue(Constants.HeaderKeys.RPTenantId, out var messageTenantId))
            {
                controlMessage.UserProperties.Add(Constants.HeaderKeys.RPTenantId, messageTenantId);
            }

            controlMessage.ScheduledEnqueueTimeUtc = DateTime.UtcNow.Add(tryAgainIn);
            controlMessage.PartitionKey            = _message.PartitionKey; // Ensure the control message goes to the same partition as the underlying message so transactions work

            // We want to use a transaction if we're not already in a transaction scope
            var useTransaction = !_isTransactional;

            using (var tx = useTransaction ? new TransactionScope(TransactionScopeAsyncFlowOption.Enabled) : null)
            {
                await sender.SendAsync(controlMessage).ConfigureAwait(false);

                if (_deferralControlMessage == null)
                {
                    await _messageReceiver.DeferAsync(_message.SystemProperties.LockToken)
                    .ConfigureAwait(false);
                }
                else
                {
                    await _messageReceiver.AbandonAsync(_message.SystemProperties.LockToken)
                    .ConfigureAwait(false);
                }

                // If we are deferring a message that was already deferred, we are sending a new control message, so complete
                // the current control message.
                if (_deferralControlMessage != null)
                {
                    await _messageReceiver.CompleteAsync(_deferralControlMessage.SystemProperties.LockToken).ConfigureAwait(false);
                }

                tx?.Complete();
            }
        }
Пример #4
0
        static async Task Sender()
        {
            var queue  = "myfirstqueue";
            var sender = new Microsoft.Azure.ServiceBus.Core.MessageSender(NamespaceConnectionString, queue);
            var text   = Console.ReadLine();

            while (text != "q")
            {
                var message           = new Microsoft.Azure.ServiceBus.Message(System.Text.Encoding.UTF8.GetBytes(text));
                var messageWithOffset = new Microsoft.Azure.ServiceBus.Message(System.Text.Encoding.UTF8.GetBytes(text + " with offset"));

                await sender.ScheduleMessageAsync(messageWithOffset, DateTimeOffset.Now.AddSeconds(3));

                await sender.SendAsync(message);

                text = Console.ReadLine();
            }

            await sender.CloseAsync();
        }
        public async Task SendAsync(IList <Message> messageList)
        {
            int count = MessageSender.ValidateMessages(messageList);

            MessagingEventSource.Log.MessageSendStart(this.ClientId, count);

            try
            {
                await this.RetryPolicy.RunOperation(
                    async() =>
                {
                    await this.OnSendAsync(messageList).ConfigureAwait(false);
                }, this.OperationTimeout)
                .ConfigureAwait(false);
            }
            catch (Exception exception)
            {
                MessagingEventSource.Log.MessageSendException(this.ClientId, exception);
                throw;
            }

            MessagingEventSource.Log.MessageSendStop(this.ClientId);
        }
        public async Task Run(ILogger logger, Message message, MessageReceiver messageReceiver, Microsoft.Azure.ServiceBus.Core.MessageSender messageSender)
        {
            _logger = logger;
            var messageString = Encoding.UTF8.GetString(message.Body);
            var jsonMessage   = JsonConvert.DeserializeObject <ExampleMessageType>(messageString);

            //  Process our job and forward the order
            var result = await TryProcessJobAsync(jsonMessage);

            //  Examine results. Log information and Retry job if necessary
            var lockToken = message.SystemProperties.LockToken;

            switch (result)
            {
            case ResultCode.Success:
                logger.LogInformation($"Completed the message {message.MessageId} due to successful handling.");
                break;

            case ResultCode.TemporaryFailure:
                int resubmitCount = message.UserProperties.ContainsKey("ResubmitCount") ? (int)message.UserProperties["ResubmitCount"] : 0;
                if (resubmitCount > 5)
                {
                    await messageReceiver.DeadLetterAsync(lockToken, "Exceeded max retries", GetDeadLetterDescription());

                    logger.LogInformation("$Dead lettered the message due to exceeding max retries, this will need to be retried manually.");
                }
                else
                {
                    await ResubmitMessageAsync(message, messageSender, resubmitCount);

                    logger.LogInformation($"Resubmitted the message {message.MessageId} to be tried again in {RetryTemporaryErrorsAfterMinutes} minutes");
                }
                break;

            case ResultCode.PermanentFailure:
                await messageReceiver.DeadLetterAsync(lockToken, "Permanent failure", GetDeadLetterDescription());

                logger.LogInformation("$Dead lettered the message due to a permanent failure, this will need to be retried manually.");
                break;

            default:
                break;
            }
            LogProgress();
            if (result != ResultCode.Success)
            {
                // throw an error so the function fails and we can see it as an error in azure functions monitor logs
                throw new Exception("There were one or more errors during job");
            }
        }