public async Task ReceiveMessagesWhenQueueEmpty()
        {
            await using (var scope = await ServiceBusScope.CreateWithQueue(enablePartitioning: false, enableSession: true))
            {
                await using var client = new ServiceBusClient(TestEnvironment.ServiceBusConnectionString, new ServiceBusClientOptions
                {
                    RetryOptions =
                    {
                        // very high TryTimeout
                        TryTimeout = TimeSpan.FromSeconds(120)
                    }
                });

                var messageCount        = 2;
                var sessionId           = "sessionId1";
                ServiceBusSender sender = client.CreateSender(scope.QueueName);
                using ServiceBusMessageBatch batch = await sender.CreateMessageBatchAsync();

                IEnumerable <ServiceBusMessage> messages = AddMessages(batch, messageCount, sessionId).AsEnumerable <ServiceBusMessage>();
                await sender.SendMessagesAsync(batch);

                ServiceBusReceiver receiver = await client.AcceptNextSessionAsync(
                    scope.QueueName,
                    new ServiceBusSessionReceiverOptions
                {
                    PrefetchCount = 100
                });

                var remainingMessages = messageCount;
                while (remainingMessages > 0)
                {
                    foreach (var message in await receiver.ReceiveMessagesAsync(remainingMessages))
                    {
                        await receiver.CompleteMessageAsync(message);

                        remainingMessages--;
                    }
                }

                using var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(3));

                var start = DateTime.UtcNow;
                Assert.ThrowsAsync <TaskCanceledException>(async() => await receiver.ReceiveMessagesAsync(1, cancellationToken: cancellationTokenSource.Token));
                var stop = DateTime.UtcNow;

                Assert.That(stop - start, Is.EqualTo(TimeSpan.FromSeconds(3)).Within(TimeSpan.FromSeconds(3)));
            }
        }
Beispiel #2
0
        public async Task AbandonMessages(bool useSpecificSession)
        {
            await using (var scope = await ServiceBusScope.CreateWithQueue(enablePartitioning: false, enableSession: true))
            {
                await using var client = new ServiceBusClient(TestEnvironment.ServiceBusConnectionString);
                ServiceBusSender sender = client.CreateSender(scope.QueueName);

                var messageCount = 10;
                var sessionId    = "sessionId1";
                using ServiceBusMessageBatch batch = await sender.CreateMessageBatchAsync();

                IEnumerable <ServiceBusMessage> messages = AddMessages(batch, messageCount, sessionId).AsEnumerable <ServiceBusMessage>();

                await sender.SendMessagesAsync(batch);

                ServiceBusReceiver receiver = await client.CreateSessionReceiverAsync(
                    scope.QueueName,
                    new ServiceBusSessionReceiverOptions
                {
                    SessionId = useSpecificSession ? sessionId : null
                });

                var messageEnum       = messages.GetEnumerator();
                var remainingMessages = messageCount;
                IList <ServiceBusReceivedMessage> receivedMessages = new List <ServiceBusReceivedMessage>();

                while (remainingMessages > 0)
                {
                    foreach (var msg in await receiver.ReceiveMessagesAsync(remainingMessages))
                    {
                        remainingMessages--;
                        messageEnum.MoveNext();
                        Assert.AreEqual(messageEnum.Current.MessageId, msg.MessageId);
                        Assert.AreEqual(messageEnum.Current.SessionId, msg.SessionId);
                        receivedMessages.Add(msg);
                        Assert.AreEqual(msg.DeliveryCount, 1);
                    }
                }
                Assert.AreEqual(0, remainingMessages);

                // don't abandon in the receive loop
                // as this would make the message available to be immediately received again
                foreach (var msg in receivedMessages)
                {
                    await receiver.AbandonMessageAsync(msg);
                }

                messageEnum.Reset();
                var receivedMessageCount = 0;
                foreach (var item in await receiver.PeekMessagesAsync(messageCount))
                {
                    receivedMessageCount++;
                    messageEnum.MoveNext();
                    Assert.AreEqual(messageEnum.Current.MessageId, item.MessageId);
                    Assert.AreEqual(messageEnum.Current.SessionId, item.SessionId);
                }
                Assert.AreEqual(messageCount, receivedMessageCount);
            }
        }
        public async Task <IReadOnlyList <ServiceBusReceivedMessage> > ReceiveAsync()
        {
            var messages = await _messageReceiver.ReceiveMessagesAsync(_batchSize, _timeout).ConfigureAwait(false);

            return(messages != null
                ? messages.ToList()
                : Array.Empty <ServiceBusReceivedMessage>());
        }
Beispiel #4
0
        public async Task ReceiveBatchOfMessagesLogsEvents()
        {
            var mockLogger            = new Mock <ServiceBusEventSource>();
            var maxMessages           = 4;
            var mockTransportReceiver = new Mock <TransportReceiver>();
            var mockConnection        = GetMockConnection(mockTransportReceiver);

            mockTransportReceiver.Setup(
                transportReceiver => transportReceiver.ReceiveMessagesAsync(
                    maxMessages,
                    It.IsAny <TimeSpan?>(),
                    false,
                    It.IsAny <CancellationToken>()))
            .Returns(
                Task.FromResult((IReadOnlyList <ServiceBusReceivedMessage>)
                                new List <ServiceBusReceivedMessage> {
                new ServiceBusReceivedMessage(),
                new ServiceBusReceivedMessage()
            }));
            var receiver = new ServiceBusReceiver(
                mockConnection.Object,
                "queueName",
                false,
                new ServiceBusPlugin[] { },
                new ServiceBusReceiverOptions()
            {
                PrefetchCount = maxMessages - 1
            })
            {
                Logger = mockLogger.Object
            };

            var msgs = await receiver.ReceiveMessagesAsync(maxMessages : maxMessages);

            mockLogger
            .Verify(
                log => log.ReceiveMessageStart(
                    receiver.Identifier,
                    // the amount requested
                    maxMessages),
                Times.Once);

            mockLogger
            .Verify(
                log => log.MaxMessagesExceedsPrefetch(
                    receiver.Identifier,
                    receiver.PrefetchCount,
                    maxMessages),
                Times.Once);
            mockLogger
            .Verify(
                log => log.ReceiveMessageComplete(
                    receiver.Identifier,
                    // the amount we actually received
                    msgs.Count),
                Times.Once);
        }
Beispiel #5
0
        public async Task <IEnumerable <IBrokeredMessageWrapper> > Receive(int batchSize, TimeSpan serverWaitTime)
        {
            var messages = await _messageReceiver.ReceiveMessagesAsync(batchSize, serverWaitTime).ConfigureAwait(false);

            if (messages == null)
            {
                return(new List <IBrokeredMessageWrapper>());
            }
            return(messages.Select(x => new BrokeredMessageWrapper(x)));
        }
        private async Task ProcessMessages(string platform, CancellationToken stoppingToken)
        {
            await using ServiceBusReceiver receiver = _sBusClient.CreateReceiver(topicName, platform);

            await foreach (var message in receiver.ReceiveMessagesAsync(stoppingToken))
            {
                _logger.LogInformation("New show message received for {Platform}", platform);
                _logger.LogInformation($"Show Message ID=> {message.MessageId}");
                _logger.LogInformation($"Show Message Body=> {message.Body.ToString()}");
                await receiver.CompleteMessageAsync(message, stoppingToken);
            }
        }
        private async Task ProcessMessages(CancellationToken stoppingToken)
        {
            ServiceBusReceiver receiver = _sBusClient.CreateReceiver(queueName);

            await foreach (var message in receiver.ReceiveMessagesAsync(stoppingToken))
            {
                _logger.LogInformation("Message received");
                _logger.LogInformation($"Message ID=> {message.MessageId}");
                _logger.LogInformation($"Message Body=> {message.Body.ToString()}");
                await receiver.CompleteMessageAsync(message, stoppingToken);
            }
        }
        private async Task ReceiveMessages(string subscription)
        {
            await using var client = new ServiceBusClient(ServiceBusConnectionString);
            ServiceBusReceiver receiver = client.CreateReceiver(TopicName, subscription);

            // In reality you would not break out of the loop like in this example but would keep looping. The receiver keeps the connection open
            // to the broker for the specified amount of seconds and the broker returns messages as soon as they arrive. The client then initiates
            // a new connection. So in reality you would not want to break out of the loop.
            // Also note that the code shows how to batch receive, which you would do for performance reasons. For convenience you can also always
            // use the regular receive pump which we show in our Quick Start and in other github samples.
            while (true)
            {
                try
                {
                    //IList<Message> messages = await receiver.ReceiveAsync(10, TimeSpan.FromSeconds(2));
                    // Note the extension class which is serializing an deserializing messages and testing messages is null or 0.
                    // If you think you did not receive all messages, just press M and receive again via the menu.
                    IReadOnlyList <ServiceBusReceivedMessage> messages = await receiver.ReceiveMessagesAsync(maxMessages : 100);

                    if (messages.Any())
                    {
                        foreach (ServiceBusReceivedMessage message in messages)
                        {
                            lock (Console.Out)
                            {
                                Item item = message.As <Item>();
                                IReadOnlyDictionary <string, object> myUserProperties = message.ApplicationProperties;
                                Console.WriteLine($"StoreId={myUserProperties["StoreId"]}");
                                if (message.Subject != null)
                                {
                                    Console.WriteLine($"Subject={message.Subject}");
                                }
                                Console.WriteLine(
                                    $"Item data: Price={item.GetPrice()}, Color={item.GetColor()}, Category={item.GetItemCategory()}");
                            }

                            await receiver.CompleteMessageAsync(message);
                        }
                    }
                    else
                    {
                        break;
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.ToString());
                }
            }
        }
        public async Task SendAndReceiveMessageBatch()
        {
            await using (var scope = await ServiceBusScope.CreateWithQueue(enablePartitioning: false, enableSession: false))
            {
                #region Snippet:ServiceBusInitializeSend
#if SNIPPET
                string connectionString = "<connection_string>";
                string queueName        = "<queue_name>";
#else
                string connectionString = TestEnvironment.ServiceBusConnectionString;
                string queueName        = scope.QueueName;
#endif
                // since ServiceBusClient implements IAsyncDisposable we create it with "await using"
                await using var client = new ServiceBusClient(connectionString);

                // create the sender
                ServiceBusSender sender = client.CreateSender(queueName);
                #region Snippet:ServiceBusSendAndReceiveBatch
                IList <ServiceBusMessage> messages = new List <ServiceBusMessage>();
                messages.Add(new ServiceBusMessage("First"));
                messages.Add(new ServiceBusMessage("Second"));
                // send the messages
                await sender.SendMessagesAsync(messages);

                #endregion
                #endregion
                #region Snippet:ServiceBusReceiveBatch
                // create a receiver that we can use to receive the messages
                ServiceBusReceiver receiver = client.CreateReceiver(queueName);

                // the received message is a different type as it contains some service set properties
                IReadOnlyList <ServiceBusReceivedMessage> receivedMessages = await receiver.ReceiveMessagesAsync(maxMessages : 2);

                foreach (ServiceBusReceivedMessage receivedMessage in receivedMessages)
                {
                    // get the message body as a string
                    string body = receivedMessage.Body.ToString();
                    Console.WriteLine(body);
                }
                #endregion

                var sentMessagesEnum = messages.GetEnumerator();
                foreach (ServiceBusReceivedMessage receivedMessage in receivedMessages)
                {
                    sentMessagesEnum.MoveNext();
                    Assert.AreEqual(sentMessagesEnum.Current.Body.ToString(), receivedMessage.Body.ToString());
                }
            }
        }
        public async Task SendAndReceiveMessageSafeBatch()
        {
            await using (var scope = await ServiceBusScope.CreateWithQueue(enablePartitioning: false, enableSession: false))
            {
                string connectionString = TestEnvironment.ServiceBusConnectionString;
                string queueName        = scope.QueueName;

                //@@ string connectionString = "<connection_string>";
                //@@ string queueName = "<queue_name>";
                // since ServiceBusClient implements IAsyncDisposable we create it with "await using"
                await using var client = new ServiceBusClient(connectionString);

                // create the sender
                ServiceBusSender sender = client.CreateSender(queueName);

                // create a message batch that we can send
                #region Snippet:ServiceBusSendAndReceiveSafeBatch
                ServiceBusMessageBatch messageBatch = await sender.CreateMessageBatchAsync();

                messageBatch.TryAddMessage(new ServiceBusMessage(Encoding.UTF8.GetBytes("First")));
                messageBatch.TryAddMessage(new ServiceBusMessage(Encoding.UTF8.GetBytes("Second")));

                // send the message batch
                await sender.SendMessagesAsync(messageBatch);

                #endregion

                // create a receiver that we can use to receive the messages
                ServiceBusReceiver receiver = client.CreateReceiver(queueName);

                // the received message is a different type as it contains some service set properties
                IReadOnlyList <ServiceBusReceivedMessage> receivedMessages = await receiver.ReceiveMessagesAsync(maxMessages : 2);

                foreach (ServiceBusReceivedMessage receivedMessage in receivedMessages)
                {
                    // get the message body as a string using an implicit cast
                    string body = receivedMessage.Body.ToString();
                }
                var sentMessagesEnum = messageBatch.AsEnumerable <ServiceBusMessage>().GetEnumerator();
                foreach (ServiceBusReceivedMessage receivedMessage in receivedMessages)
                {
                    sentMessagesEnum.MoveNext();
                    Assert.AreEqual(sentMessagesEnum.Current.Body.ToString(), receivedMessage.Body.ToString());
                }
            }
        }
Beispiel #11
0
        public async Task ReceiveMessagesInReceiveAndDeleteMode()
        {
            await using (var scope = await ServiceBusScope.CreateWithQueue(enablePartitioning: false, enableSession: true))
            {
                await using var client = new ServiceBusClient(TestEnvironment.ServiceBusConnectionString);
                ServiceBusSender sender = client.CreateSender(scope.QueueName);

                var messageCount = 10;
                var sessionId    = "sessionId1";
                using ServiceBusMessageBatch batch = await sender.CreateMessageBatchAsync();

                IEnumerable <ServiceBusMessage> messages = AddMessages(batch, messageCount, sessionId).AsEnumerable <ServiceBusMessage>();

                await sender.SendMessagesAsync(batch);

                var clientOptions = new ServiceBusSessionReceiverOptions
                {
                    ReceiveMode = ServiceBusReceiveMode.ReceiveAndDelete
                };

                ServiceBusReceiver receiver = await client.AcceptSessionAsync(
                    scope.QueueName,
                    sessionId,
                    clientOptions);

                var remainingMessages = messageCount;
                var messageEnum       = messages.GetEnumerator();

                while (remainingMessages > 0)
                {
                    foreach (var item in await receiver.ReceiveMessagesAsync(remainingMessages))
                    {
                        messageEnum.MoveNext();
                        Assert.AreEqual(messageEnum.Current.MessageId, item.MessageId);
                        Assert.AreEqual(messageEnum.Current.SessionId, item.SessionId);
                        remainingMessages--;
                    }
                }
                Assert.AreEqual(0, remainingMessages);

                var peekedMessage = receiver.PeekMessageAsync();
                Assert.IsNull(peekedMessage.Result);
            }
        }
Beispiel #12
0
        public static async Task ReceivedMessagesAsync(ServiceBusReceiver serviceBusReceiver, string subscriber)
        {
            while (true)
            {
                var receivedMessage = await serviceBusReceiver.ReceiveMessagesAsync(1, TimeSpan.FromSeconds(1));

                if (receivedMessage == null || receivedMessage.Count == 0)
                {
                    break;
                }

                foreach (var message in receivedMessage)
                {
                    var body          = message.Body.ToString();
                    var msgPropNumber = message.ApplicationProperties["MsgProp"];
                    Console.WriteLine($"{subscriber}\t{msgPropNumber}\t{body}");
                }
            }
        }
Beispiel #13
0
        public async Task ReceiveMessagesInPeekLockMode()
        {
            await using (var scope = await ServiceBusScope.CreateWithQueue(enablePartitioning: false, enableSession: true))
            {
                await using var client = new ServiceBusClient(TestEnvironment.ServiceBusConnectionString);
                ServiceBusSender sender = client.CreateSender(scope.QueueName);

                var messageCount = 10;
                var sessionId    = "sessionId1";
                using ServiceBusMessageBatch batch = await sender.CreateMessageBatchAsync();

                IEnumerable <ServiceBusMessage> messages = AddMessages(batch, messageCount, sessionId).AsEnumerable <ServiceBusMessage>();

                await sender.SendMessagesAsync(batch);

                ServiceBusReceiver receiver = await client.AcceptNextSessionAsync(
                    scope.QueueName,
                    new ServiceBusSessionReceiverOptions
                {
                    PrefetchCount = 100
                });

                var messageEnum = messages.GetEnumerator();

                foreach (var item in await receiver.ReceiveMessagesAsync(messageCount))
                {
                    messageEnum.MoveNext();
                    Assert.AreEqual(messageEnum.Current.MessageId, item.MessageId);
                    Assert.AreEqual(messageEnum.Current.SessionId, item.SessionId);
                    Assert.AreEqual(item.DeliveryCount, 1);
                }

                messageEnum.Reset();
                foreach (var item in await receiver.PeekMessagesAsync(messageCount))
                {
                    messageEnum.MoveNext();
                    Assert.AreEqual(messageEnum.Current.MessageId, item.MessageId);
                    Assert.AreEqual(messageEnum.Current.SessionId, item.SessionId);
                }
            }
        }
        static async Task ReceiveAndProcess(string topicName, string subscriptionName, ILogger log)
        {
            log.LogInformation($"Topic: {topicName} Subscription: {subscriptionName}");

            // crate a Service Bus Client using the connection string
            ServiceBusClient client = new ServiceBusClient(ServiceBusConnectionString);

            // create the receiver
            ServiceBusReceiver receiver = client.CreateReceiver(topicName, subscriptionName);

            // receive messages
            IReadOnlyList <ServiceBusReceivedMessage> receivedMessages = await receiver.ReceiveMessagesAsync(maxMessages : 100);

            foreach (ServiceBusReceivedMessage receivedMessage in receivedMessages)
            {
                // get the message body as a string
                string body = receivedMessage.Body.ToString();
                log.LogInformation($"Received: {body} from subscription: {subscriptionName}");
                // complete the message, thereby deleting it from the service
                await receiver.CompleteMessageAsync(receivedMessage);
            }
        }
        public async Task CompleteMessages(bool useSpecificSession)
        {
            await using (var scope = await ServiceBusScope.CreateWithQueue(enablePartitioning: false, enableSession: true))
            {
                await using var client = new ServiceBusClient(TestEnvironment.ServiceBusConnectionString);
                ServiceBusSender sender = client.CreateSender(scope.QueueName);

                var messageCount = 10;
                var sessionId    = "sessionId1";
                using ServiceBusMessageBatch batch = await sender.CreateMessageBatchAsync();

                IEnumerable <ServiceBusMessage> messages = ServiceBusTestUtilities.AddMessages(batch, messageCount, sessionId).AsReadOnly <ServiceBusMessage>();

                await sender.SendMessagesAsync(batch);

                ServiceBusReceiver receiver = await client.AcceptSessionAsync(
                    scope.QueueName,
                    useSpecificSession?sessionId : null);

                var messageEnum       = messages.GetEnumerator();
                var remainingMessages = messageCount;

                while (remainingMessages > 0)
                {
                    foreach (var item in await receiver.ReceiveMessagesAsync(remainingMessages))
                    {
                        remainingMessages--;
                        messageEnum.MoveNext();
                        Assert.AreEqual(messageEnum.Current.MessageId, item.MessageId);
                        Assert.AreEqual(messageEnum.Current.SessionId, item.SessionId);
                        await receiver.CompleteMessageAsync(item);
                    }
                }
                Assert.AreEqual(0, remainingMessages);

                var peekedMessage = receiver.PeekMessageAsync();
                Assert.IsNull(peekedMessage.Result);
            }
        }
Beispiel #16
0
        private async Task RunBatchReceiveLoopAsync(CancellationToken cancellationToken)
        {
            ServiceBusClient   sessionClient = null;
            ServiceBusReceiver receiver      = null;

            if (_isSessionsEnabled)
            {
                sessionClient = _client.Value;
            }
            else
            {
                receiver = _batchReceiver.Value;
            }

            // The batch receive loop below only executes functions at a concurrency level of 1,
            // so we don't need to do anything special when DynamicConcurrency is enabled. If in
            // the future we make this loop concurrent, we'll have to check with ConcurrencyManager.
            while (true)
            {
                try
                {
                    if (cancellationToken.IsCancellationRequested)
                    {
                        _logger.LogInformation($"Message processing has been stopped or cancelled ({_details.Value})");
                        return;
                    }

                    if (_isSessionsEnabled && (receiver == null || receiver.IsClosed))
                    {
                        try
                        {
                            receiver = await sessionClient.AcceptNextSessionAsync(
                                _entityPath,
                                new ServiceBusSessionReceiverOptions
                            {
                                PrefetchCount = _serviceBusOptions.PrefetchCount
                            },
                                cancellationToken).ConfigureAwait(false);
                        }
                        catch (ServiceBusException ex)
                            when(ex.Reason == ServiceBusFailureReason.ServiceTimeout)
                            {
                                // it's expected if the entity is empty, try next time
                                continue;
                            }
                    }

                    IReadOnlyList <ServiceBusReceivedMessage> messages =
                        await receiver.ReceiveMessagesAsync(
                            _serviceBusOptions.MaxMessageBatchSize,
                            cancellationToken : cancellationToken).AwaitWithCancellation(cancellationToken);

                    if (messages.Count > 0)
                    {
                        var messageActions = _isSessionsEnabled
                            ? new ServiceBusSessionMessageActions((ServiceBusSessionReceiver)receiver)
                            : new ServiceBusMessageActions(receiver);
                        var receiveActions = new ServiceBusReceiveActions(receiver);

                        ServiceBusReceivedMessage[] messagesArray = messages.ToArray();
                        ServiceBusTriggerInput      input         = ServiceBusTriggerInput.CreateBatch(
                            messagesArray,
                            messageActions,
                            receiveActions,
                            _client.Value);

                        FunctionResult result = await _triggerExecutor.TryExecuteAsync(input.GetTriggerFunctionData(), cancellationToken).ConfigureAwait(false);

                        receiveActions.EndExecutionScope();

                        var processedMessages = messagesArray.Concat(receiveActions.Messages.Keys);
                        // Complete batch of messages only if the execution was successful
                        if (_autoCompleteMessages && result.Succeeded)
                        {
                            List <Task> completeTasks = new List <Task>();
                            foreach (ServiceBusReceivedMessage message in processedMessages)
                            {
                                // skip messages that were settled in the user's function
                                if (input.MessageActions.SettledMessages.ContainsKey(message))
                                {
                                    continue;
                                }

                                // Pass CancellationToken.None to allow autocompletion to finish even when shutting down
                                completeTasks.Add(receiver.CompleteMessageAsync(message, CancellationToken.None));
                            }

                            await Task.WhenAll(completeTasks).ConfigureAwait(false);
                        }
                        else if (!result.Succeeded)
                        {
                            // For failed executions, we abandon the messages regardless of the autoCompleteMessages configuration.
                            // This matches the behavior that happens for single dispatch functions as the processor does the same thing
                            // in the Service Bus SDK.

                            List <Task> abandonTasks = new List <Task>();
                            foreach (ServiceBusReceivedMessage message in processedMessages)
                            {
                                // skip messages that were settled in the user's function
                                if (input.MessageActions.SettledMessages.ContainsKey(message))
                                {
                                    continue;
                                }

                                // Pass CancellationToken.None to allow abandon to finish even when shutting down
                                abandonTasks.Add(receiver.AbandonMessageAsync(message, cancellationToken: CancellationToken.None));
                            }

                            await Task.WhenAll(abandonTasks).ConfigureAwait(false);
                        }

                        if (_isSessionsEnabled)
                        {
                            if (((ServiceBusSessionMessageActions)messageActions).ShouldReleaseSession)
                            {
                                // Use CancellationToken.None to attempt to close the receiver even when shutting down
                                await receiver.CloseAsync(CancellationToken.None).ConfigureAwait(false);
                            }
                        }
                    }
                    else
                    {
                        // Close the session and release the session lock after draining all messages for the accepted session.
                        if (_isSessionsEnabled)
                        {
                            // Use CancellationToken.None to attempt to close the receiver even when shutting down
                            await receiver.CloseAsync(CancellationToken.None).ConfigureAwait(false);
                        }
                    }
                }
                catch (ObjectDisposedException)
                {
                    // Ignore as we are stopping the host
                }
                catch (OperationCanceledException)
                    when(cancellationToken.IsCancellationRequested)
                    {
                        // Ignore as we are stopping the host
                        _logger.LogInformation($"Message processing has been stopped or cancelled ({_details.Value})");
                    }
                catch (Exception ex)
                {
                    // Log another exception
                    _logger.LogError(ex, $"An unhandled exception occurred in the message batch receive loop ({_details.Value})");

                    if (_isSessionsEnabled && receiver != null)
                    {
                        // Attempt to close the session and release session lock to accept a new session on the next loop iteration
                        try
                        {
                            // Use CancellationToken.None to attempt to close the receiver even when shutting down
                            await receiver.CloseAsync(CancellationToken.None).ConfigureAwait(false);
                        }
                        catch
                        {
                            // Best effort
                            receiver = null;
                        }
                    }
                }
            }
        }
        public async Task SendAndReceiveMessageSafeBatch()
        {
            await using (var scope = await ServiceBusScope.CreateWithQueue(enablePartitioning: false, enableSession: false))
            {
#if SNIPPET
                string connectionString = "<connection_string>";
                string queueName        = "<queue_name>";
#else
                string connectionString = TestEnvironment.ServiceBusConnectionString;
                string queueName        = scope.QueueName;
#endif
                // since ServiceBusClient implements IAsyncDisposable we create it with "await using"
                await using var client = new ServiceBusClient(connectionString);

                // create the sender
                ServiceBusSender sender = client.CreateSender(queueName);

                #region Snippet:ServiceBusSendAndReceiveSafeBatch
                // add the messages that we plan to send to a local queue
                Queue <ServiceBusMessage> messages = new Queue <ServiceBusMessage>();
                messages.Enqueue(new ServiceBusMessage("First message"));
                messages.Enqueue(new ServiceBusMessage("Second message"));
                messages.Enqueue(new ServiceBusMessage("Third message"));

                // create a message batch that we can send
                // total number of messages to be sent to the Service Bus queue
                int messageCount = messages.Count;

                // while all messages are not sent to the Service Bus queue
                while (messages.Count > 0)
                {
                    // start a new batch
                    using ServiceBusMessageBatch messageBatch = await sender.CreateMessageBatchAsync();

                    // add the first message to the batch
                    if (messageBatch.TryAddMessage(messages.Peek()))
                    {
                        // dequeue the message from the .NET queue once the message is added to the batch
                        messages.Dequeue();
                    }
                    else
                    {
                        // if the first message can't fit, then it is too large for the batch
                        throw new Exception($"Message {messageCount - messages.Count} is too large and cannot be sent.");
                    }

                    // add as many messages as possible to the current batch
                    while (messages.Count > 0 && messageBatch.TryAddMessage(messages.Peek()))
                    {
                        // dequeue the message from the .NET queue as it has been added to the batch
                        messages.Dequeue();
                    }

                    // now, send the batch
                    await sender.SendMessagesAsync(messageBatch);

                    // if there are any remaining messages in the .NET queue, the while loop repeats
                }
                #endregion

                // create a receiver that we can use to receive the messages
                ServiceBusReceiver receiver = client.CreateReceiver(queueName);

                // the received message is a different type as it contains some service set properties
                IReadOnlyList <ServiceBusReceivedMessage> receivedMessages = await receiver.ReceiveMessagesAsync(maxMessages : 2);

                foreach (ServiceBusReceivedMessage receivedMessage in receivedMessages)
                {
                    // get the message body as a string
                    string body = receivedMessage.Body.ToString();
                }
            }
        }
 public async Task <IReadOnlyList <ServiceBusReceivedMessage> > ReceiveMessagesAsync(ServiceBusReceiver serviceBusReceiver)
 {
     return(await serviceBusReceiver.ReceiveMessagesAsync(batchMessageCountLimit, new TimeSpan(0, 0, 5)));
 }
        public async Task SenderReceiverActivities(bool useSessions)
        {
            await using (var scope = await ServiceBusScope.CreateWithQueue(enablePartitioning: false, enableSession: useSessions))
            {
                using var listener = new TestDiagnosticListener(EntityScopeFactory.DiagnosticNamespace);
                var client = new ServiceBusClient(TestEnvironment.ServiceBusConnectionString);
                ServiceBusSender sender    = client.CreateSender(scope.QueueName);
                string           sessionId = null;
                if (useSessions)
                {
                    sessionId = "sessionId";
                }
                int numMessages = 5;
                var msgs        = GetMessages(numMessages, sessionId);
                await sender.SendMessagesAsync(msgs);

                Activity[] sendActivities = AssertSendActivities(useSessions, sender, msgs, listener);

                ServiceBusReceiver receiver = null;
                if (useSessions)
                {
                    receiver = await client.CreateSessionReceiverAsync(scope.QueueName);
                }
                else
                {
                    receiver = client.CreateReceiver(scope.QueueName);
                }

                var remaining = numMessages;
                List <ServiceBusReceivedMessage> receivedMsgs = new List <ServiceBusReceivedMessage>();
                while (remaining > 0)
                {
                    // loop in case we don't receive all messages in one attempt
                    var received = await receiver.ReceiveMessagesAsync(remaining);

                    receivedMsgs.AddRange(received);
                    (string Key, object Value, DiagnosticListener)receiveStart = listener.Events.Dequeue();
                    Assert.AreEqual(DiagnosticProperty.ReceiveActivityName + ".Start", receiveStart.Key);

                    Activity receiveActivity = (Activity)receiveStart.Value;
                    AssertCommonTags(receiveActivity, receiver.EntityPath, receiver.FullyQualifiedNamespace);
                    CollectionAssert.Contains(
                        receiveActivity.Tags,
                        new KeyValuePair <string, string>(
                            DiagnosticProperty.RequestedMessageCountAttribute,
                            remaining.ToString()));
                    CollectionAssert.Contains(
                        receiveActivity.Tags,
                        new KeyValuePair <string, string>(
                            DiagnosticProperty.MessageIdAttribute,
                            string.Join(",", received.Select(m => m.MessageId).ToArray())));
                    remaining -= received.Count;

                    if (useSessions)
                    {
                        CollectionAssert.Contains(
                            receiveActivity.Tags,
                            new KeyValuePair <string, string>(
                                DiagnosticProperty.SessionIdAttribute,
                                string.Join(",", msgs.Select(m => m.SessionId).Distinct().ToArray())));
                    }
                    var receiveLinkedActivities = ((IEnumerable <Activity>)receiveActivity.GetType().GetProperty("Links").GetValue(receiveActivity)).ToArray();
                    for (int i = 0; i < receiveLinkedActivities.Length; i++)
                    {
                        Assert.AreEqual(sendActivities[i].ParentId, receiveLinkedActivities[i].ParentId);
                    }
                    (string Key, object Value, DiagnosticListener)receiveStop = listener.Events.Dequeue();

                    Assert.AreEqual(DiagnosticProperty.ReceiveActivityName + ".Stop", receiveStop.Key);
                }

                var msgIndex = 0;

                var completed = receivedMsgs[msgIndex];
                await receiver.CompleteMessageAsync(completed);

                (string Key, object Value, DiagnosticListener)completeStart = listener.Events.Dequeue();
                Assert.AreEqual(DiagnosticProperty.CompleteActivityName + ".Start", completeStart.Key);
                Activity completeActivity = (Activity)completeStart.Value;
                AssertCommonTags(completeActivity, receiver.EntityPath, receiver.FullyQualifiedNamespace);
                AssertLockTokensTag(completeActivity, completed.LockToken);
                (string Key, object Value, DiagnosticListener)completeStop = listener.Events.Dequeue();
                Assert.AreEqual(DiagnosticProperty.CompleteActivityName + ".Stop", completeStop.Key);

                var deferred = receivedMsgs[++msgIndex];
                await receiver.DeferMessageAsync(deferred);

                (string Key, object Value, DiagnosticListener)deferStart = listener.Events.Dequeue();
                Assert.AreEqual(DiagnosticProperty.DeferActivityName + ".Start", deferStart.Key);
                Activity deferActivity = (Activity)deferStart.Value;
                AssertCommonTags(deferActivity, receiver.EntityPath, receiver.FullyQualifiedNamespace);
                AssertLockTokensTag(deferActivity, deferred.LockToken);
                (string Key, object Value, DiagnosticListener)deferStop = listener.Events.Dequeue();
                Assert.AreEqual(DiagnosticProperty.DeferActivityName + ".Stop", deferStop.Key);

                var deadLettered = receivedMsgs[++msgIndex];
                await receiver.DeadLetterMessageAsync(deadLettered);

                (string Key, object Value, DiagnosticListener)deadLetterStart = listener.Events.Dequeue();
                Assert.AreEqual(DiagnosticProperty.DeadLetterActivityName + ".Start", deadLetterStart.Key);
                Activity deadLetterActivity = (Activity)deadLetterStart.Value;
                AssertCommonTags(deadLetterActivity, receiver.EntityPath, receiver.FullyQualifiedNamespace);
                AssertLockTokensTag(deadLetterActivity, deadLettered.LockToken);
                (string Key, object Value, DiagnosticListener)deadletterStop = listener.Events.Dequeue();
                Assert.AreEqual(DiagnosticProperty.DeadLetterActivityName + ".Stop", deadletterStop.Key);

                var abandoned = receivedMsgs[++msgIndex];
                await receiver.AbandonMessageAsync(abandoned);

                (string Key, object Value, DiagnosticListener)abandonStart = listener.Events.Dequeue();
                Assert.AreEqual(DiagnosticProperty.AbandonActivityName + ".Start", abandonStart.Key);
                Activity abandonActivity = (Activity)abandonStart.Value;
                AssertCommonTags(abandonActivity, receiver.EntityPath, receiver.FullyQualifiedNamespace);
                AssertLockTokensTag(abandonActivity, abandoned.LockToken);
                (string Key, object Value, DiagnosticListener)abandonStop = listener.Events.Dequeue();
                Assert.AreEqual(DiagnosticProperty.AbandonActivityName + ".Stop", abandonStop.Key);

                var receiveDeferMsg = await receiver.ReceiveDeferredMessageAsync(deferred.SequenceNumber);

                (string Key, object Value, DiagnosticListener)receiveDeferStart = listener.Events.Dequeue();
                Assert.AreEqual(DiagnosticProperty.ReceiveDeferredActivityName + ".Start", receiveDeferStart.Key);
                Activity receiveDeferActivity = (Activity)receiveDeferStart.Value;
                AssertCommonTags(receiveDeferActivity, receiver.EntityPath, receiver.FullyQualifiedNamespace);
                CollectionAssert.Contains(
                    receiveDeferActivity.Tags,
                    new KeyValuePair <string, string>(
                        DiagnosticProperty.MessageIdAttribute,
                        deferred.MessageId));
                CollectionAssert.Contains(
                    receiveDeferActivity.Tags,
                    new KeyValuePair <string, string>(
                        DiagnosticProperty.SequenceNumbersAttribute,
                        deferred.SequenceNumber.ToString()));
                (string Key, object Value, DiagnosticListener)receiveDeferStop = listener.Events.Dequeue();
                Assert.AreEqual(DiagnosticProperty.ReceiveDeferredActivityName + ".Stop", receiveDeferStop.Key);

                // renew lock
                if (useSessions)
                {
                    var sessionReceiver = (ServiceBusSessionReceiver)receiver;
                    await sessionReceiver.RenewSessionLockAsync();

                    (string Key, object Value, DiagnosticListener)renewStart = listener.Events.Dequeue();
                    Assert.AreEqual(DiagnosticProperty.RenewSessionLockActivityName + ".Start", renewStart.Key);
                    Activity renewActivity = (Activity)renewStart.Value;
                    AssertCommonTags(renewActivity, receiver.EntityPath, receiver.FullyQualifiedNamespace);
                    CollectionAssert.Contains(
                        renewActivity.Tags,
                        new KeyValuePair <string, string>(
                            DiagnosticProperty.SessionIdAttribute,
                            "sessionId"));

                    (string Key, object Value, DiagnosticListener)renewStop = listener.Events.Dequeue();
                    Assert.AreEqual(DiagnosticProperty.RenewSessionLockActivityName + ".Stop", renewStop.Key);

                    // set state
                    var state = Encoding.UTF8.GetBytes("state");
                    await sessionReceiver.SetSessionStateAsync(state);

                    (string Key, object Value, DiagnosticListener)setStateStart = listener.Events.Dequeue();
                    Assert.AreEqual(DiagnosticProperty.SetSessionStateActivityName + ".Start", setStateStart.Key);
                    Activity setStateActivity = (Activity)setStateStart.Value;
                    AssertCommonTags(setStateActivity, sessionReceiver.EntityPath, sessionReceiver.FullyQualifiedNamespace);
                    CollectionAssert.Contains(
                        setStateActivity.Tags,
                        new KeyValuePair <string, string>(
                            DiagnosticProperty.SessionIdAttribute,
                            "sessionId"));

                    (string Key, object Value, DiagnosticListener)setStateStop = listener.Events.Dequeue();
                    Assert.AreEqual(DiagnosticProperty.SetSessionStateActivityName + ".Stop", setStateStop.Key);

                    // get state
                    var getState = await sessionReceiver.GetSessionStateAsync();

                    Assert.AreEqual(state, getState);
                    (string Key, object Value, DiagnosticListener)getStateStart = listener.Events.Dequeue();
                    Assert.AreEqual(DiagnosticProperty.GetSessionStateActivityName + ".Start", getStateStart.Key);
                    Activity getStateActivity = (Activity)getStateStart.Value;
                    AssertCommonTags(getStateActivity, sessionReceiver.EntityPath, sessionReceiver.FullyQualifiedNamespace);
                    CollectionAssert.Contains(
                        getStateActivity.Tags,
                        new KeyValuePair <string, string>(
                            DiagnosticProperty.SessionIdAttribute,
                            "sessionId"));

                    (string Key, object Value, DiagnosticListener)getStateStop = listener.Events.Dequeue();
                    Assert.AreEqual(DiagnosticProperty.GetSessionStateActivityName + ".Stop", getStateStop.Key);
                }
                else
                {
                    await receiver.RenewMessageLockAsync(receivedMsgs[4]);

                    (string Key, object Value, DiagnosticListener)renewStart = listener.Events.Dequeue();
                    Assert.AreEqual(DiagnosticProperty.RenewMessageLockActivityName + ".Start", renewStart.Key);
                    Activity renewActivity = (Activity)renewStart.Value;
                    AssertCommonTags(renewActivity, receiver.EntityPath, receiver.FullyQualifiedNamespace);
                    AssertLockTokensTag(renewActivity, receivedMsgs[4].LockToken);
                    CollectionAssert.Contains(
                        renewActivity.Tags,
                        new KeyValuePair <string, string>(
                            DiagnosticProperty.LockedUntilAttribute,
                            receivedMsgs[4].LockedUntil.ToString()));

                    (string Key, object Value, DiagnosticListener)renewStop = listener.Events.Dequeue();
                    Assert.AreEqual(DiagnosticProperty.RenewMessageLockActivityName + ".Stop", renewStop.Key);
                }

                // schedule
                msgs = GetMessages(numMessages, sessionId);

                foreach (var msg in msgs)
                {
                    var seq = await sender.ScheduleMessageAsync(msg, DateTimeOffset.UtcNow.AddMinutes(1));

                    Assert.IsNotNull(msg.Properties[DiagnosticProperty.DiagnosticIdAttribute]);

                    (string Key, object Value, DiagnosticListener)startMessage = listener.Events.Dequeue();
                    Activity messageActivity = (Activity)startMessage.Value;
                    AssertCommonTags(messageActivity, sender.EntityPath, sender.FullyQualifiedNamespace);
                    Assert.AreEqual(DiagnosticProperty.MessageActivityName + ".Start", startMessage.Key);

                    (string Key, object Value, DiagnosticListener)stopMessage = listener.Events.Dequeue();
                    Assert.AreEqual(DiagnosticProperty.MessageActivityName + ".Stop", stopMessage.Key);

                    (string Key, object Value, DiagnosticListener)startSchedule = listener.Events.Dequeue();
                    AssertCommonTags((Activity)startSchedule.Value, sender.EntityPath, sender.FullyQualifiedNamespace);

                    Assert.AreEqual(DiagnosticProperty.ScheduleActivityName + ".Start", startSchedule.Key);
                    (string Key, object Value, DiagnosticListener)stopSchedule = listener.Events.Dequeue();

                    Assert.AreEqual(DiagnosticProperty.ScheduleActivityName + ".Stop", stopSchedule.Key);
                    var linkedActivities = ((IEnumerable <Activity>)startSchedule.Value.GetType().GetProperty("Links").GetValue(startSchedule.Value)).ToArray();
                    Assert.AreEqual(1, linkedActivities.Length);
                    Assert.AreEqual(messageActivity.Id, linkedActivities[0].ParentId);

                    await sender.CancelScheduledMessageAsync(seq);

                    (string Key, object Value, DiagnosticListener)startCancel = listener.Events.Dequeue();
                    AssertCommonTags((Activity)startCancel.Value, sender.EntityPath, sender.FullyQualifiedNamespace);
                    Assert.AreEqual(DiagnosticProperty.CancelActivityName + ".Start", startCancel.Key);

                    (string Key, object Value, DiagnosticListener)stopCancel = listener.Events.Dequeue();
                    Assert.AreEqual(DiagnosticProperty.CancelActivityName + ".Stop", stopCancel.Key);
                }

                // send a batch
                var batch = await sender.CreateMessageBatchAsync();

                for (int i = 0; i < numMessages; i++)
                {
                    batch.TryAddMessage(GetMessage(sessionId));
                }
                await sender.SendMessagesAsync(batch);

                AssertSendActivities(useSessions, sender, batch.AsEnumerable <ServiceBusMessage>(), listener);
            };
        }
Beispiel #20
0
        internal void StartMessageBatchReceiver(CancellationToken cancellationToken)
        {
            ServiceBusClient   sessionClient = null;
            ServiceBusReceiver receiver      = null;

            if (_isSessionsEnabled)
            {
                sessionClient = _sessionClient.Value;
            }
            else
            {
                receiver = BatchReceiver;
            }

            Task.Run(async() =>
            {
                while (true)
                {
                    try
                    {
                        if (!_started || cancellationToken.IsCancellationRequested)
                        {
                            _logger.LogInformation("Message processing has been stopped or cancelled");
                            return;
                        }

                        if (_isSessionsEnabled && (receiver == null || receiver.IsClosed))
                        {
                            try
                            {
                                receiver = await sessionClient.AcceptNextSessionAsync(_entityPath, new ServiceBusSessionReceiverOptions
                                {
                                    PrefetchCount = _serviceBusOptions.PrefetchCount
                                }).ConfigureAwait(false);
                            }
                            catch (ServiceBusException ex)
                                when(ex.Reason == ServiceBusFailureReason.ServiceTimeout)
                                {
                                    // it's expected if the entity is empty, try next time
                                    continue;
                                }
                        }

                        IReadOnlyList <ServiceBusReceivedMessage> messages =
                            await receiver.ReceiveMessagesAsync(_serviceBusOptions.MaxMessages).ConfigureAwait(false);

                        if (messages != null)
                        {
                            ServiceBusReceivedMessage[] messagesArray = messages.ToArray();
                            ServiceBusTriggerInput input = ServiceBusTriggerInput.CreateBatch(messagesArray);
                            if (_isSessionsEnabled)
                            {
                                input.MessageActions = new ServiceBusSessionMessageActions((ServiceBusSessionReceiver)receiver);
                            }
                            else
                            {
                                input.MessageActions = new ServiceBusMessageActions(receiver);
                            }
                            FunctionResult result = await _triggerExecutor.TryExecuteAsync(input.GetTriggerFunctionData(), cancellationToken).ConfigureAwait(false);

                            if (cancellationToken.IsCancellationRequested)
                            {
                                return;
                            }

                            // Complete batch of messages only if the execution was successful
                            if (_serviceBusOptions.AutoCompleteMessages && _started)
                            {
                                if (result.Succeeded)
                                {
                                    List <Task> completeTasks = new List <Task>();
                                    foreach (ServiceBusReceivedMessage message in messagesArray)
                                    {
                                        completeTasks.Add(receiver.CompleteMessageAsync(message));
                                    }
                                    await Task.WhenAll(completeTasks).ConfigureAwait(false);
                                }
                                else
                                {
                                    List <Task> abandonTasks = new List <Task>();
                                    foreach (ServiceBusReceivedMessage message in messagesArray)
                                    {
                                        abandonTasks.Add(receiver.AbandonMessageAsync(message));
                                    }
                                    await Task.WhenAll(abandonTasks).ConfigureAwait(false);
                                }
                            }
                        }
                        else
                        {
                            // Close the session and release the session lock after draining all messages for the accepted session.
                            if (_isSessionsEnabled)
                            {
                                await receiver.CloseAsync().ConfigureAwait(false);
                            }
                        }
                    }
                    catch (ObjectDisposedException)
                    {
                        // Ignore as we are stopping the host
                    }
                    catch (Exception ex)
                    {
                        // Log another exception
                        _logger.LogError(ex, $"An unhandled exception occurred in the message batch receive loop");

                        if (_isSessionsEnabled && receiver != null)
                        {
                            // Attempt to close the session and release session lock to accept a new session on the next loop iteration
                            try
                            {
                                await receiver.CloseAsync().ConfigureAwait(false);
                            }
                            catch
                            {
                                // Best effort
                                receiver = null;
                            }
                        }
                    }
                }
            }, cancellationToken);
        }
        public async Task SenderReceiverActivities(bool useSessions)
        {
            await using (var scope = await ServiceBusScope.CreateWithQueue(enablePartitioning: false, enableSession: useSessions))
            {
                var client = new ServiceBusClient(TestEnvironment.ServiceBusConnectionString);
                ServiceBusSender sender    = client.CreateSender(scope.QueueName);
                string           sessionId = null;
                if (useSessions)
                {
                    sessionId = "sessionId";
                }
                int numMessages = 5;
                var msgs        = ServiceBusTestUtilities.GetMessages(numMessages, sessionId);
                await sender.SendMessagesAsync(msgs);

                Activity[] sendActivities = AssertSendActivities(useSessions, sender, msgs);

                ServiceBusReceiver receiver = null;
                if (useSessions)
                {
                    receiver = await client.AcceptNextSessionAsync(scope.QueueName);
                }
                else
                {
                    receiver = client.CreateReceiver(scope.QueueName);
                }

                var remaining = numMessages;
                List <ServiceBusReceivedMessage> receivedMsgs = new List <ServiceBusReceivedMessage>();
                while (remaining > 0)
                {
                    // loop in case we don't receive all messages in one attempt
                    var received = await receiver.ReceiveMessagesAsync(remaining);

                    receivedMsgs.AddRange(received);
                    var receiveScope = _listener.AssertAndRemoveScope(DiagnosticProperty.ReceiveActivityName);
                    AssertCommonTags(receiveScope.Activity, receiver.EntityPath, receiver.FullyQualifiedNamespace);

                    var receiveLinkedActivities = receiveScope.LinkedActivities;
                    for (int i = 0; i < receiveLinkedActivities.Count; i++)
                    {
                        Assert.AreEqual(sendActivities[i].ParentId, receiveLinkedActivities[i].ParentId);
                    }
                    remaining -= received.Count;
                }

                var msgIndex = 0;

                var completed = receivedMsgs[msgIndex];
                await receiver.CompleteMessageAsync(completed);

                var completeScope = _listener.AssertAndRemoveScope(DiagnosticProperty.CompleteActivityName);
                AssertCommonTags(completeScope.Activity, receiver.EntityPath, receiver.FullyQualifiedNamespace);

                var deferred = receivedMsgs[++msgIndex];
                await receiver.DeferMessageAsync(deferred);

                var deferredScope = _listener.AssertAndRemoveScope(DiagnosticProperty.DeferActivityName);
                AssertCommonTags(deferredScope.Activity, receiver.EntityPath, receiver.FullyQualifiedNamespace);

                var deadLettered = receivedMsgs[++msgIndex];
                await receiver.DeadLetterMessageAsync(deadLettered);

                var deadLetterScope = _listener.AssertAndRemoveScope(DiagnosticProperty.DeadLetterActivityName);
                AssertCommonTags(deadLetterScope.Activity, receiver.EntityPath, receiver.FullyQualifiedNamespace);

                var abandoned = receivedMsgs[++msgIndex];
                await receiver.AbandonMessageAsync(abandoned);

                var abandonScope = _listener.AssertAndRemoveScope(DiagnosticProperty.AbandonActivityName);
                AssertCommonTags(abandonScope.Activity, receiver.EntityPath, receiver.FullyQualifiedNamespace);

                var receiveDeferMsg = await receiver.ReceiveDeferredMessageAsync(deferred.SequenceNumber);

                var receiveDeferScope = _listener.AssertAndRemoveScope(DiagnosticProperty.ReceiveDeferredActivityName);
                AssertCommonTags(receiveDeferScope.Activity, receiver.EntityPath, receiver.FullyQualifiedNamespace);

                // renew lock
                if (useSessions)
                {
                    var sessionReceiver = (ServiceBusSessionReceiver)receiver;
                    await sessionReceiver.RenewSessionLockAsync();

                    var renewSessionScope = _listener.AssertAndRemoveScope(DiagnosticProperty.RenewSessionLockActivityName);
                    AssertCommonTags(renewSessionScope.Activity, receiver.EntityPath, receiver.FullyQualifiedNamespace);

                    // set state
                    var state = new BinaryData("state");
                    await sessionReceiver.SetSessionStateAsync(state);

                    var setStateScope = _listener.AssertAndRemoveScope(DiagnosticProperty.SetSessionStateActivityName);
                    AssertCommonTags(setStateScope.Activity, sessionReceiver.EntityPath, sessionReceiver.FullyQualifiedNamespace);

                    // get state
                    var getState = await sessionReceiver.GetSessionStateAsync();

                    Assert.AreEqual(state.ToArray(), getState.ToArray());
                    var getStateScope = _listener.AssertAndRemoveScope(DiagnosticProperty.GetSessionStateActivityName);
                    AssertCommonTags(getStateScope.Activity, sessionReceiver.EntityPath, sessionReceiver.FullyQualifiedNamespace);
                }
                else
                {
                    await receiver.RenewMessageLockAsync(receivedMsgs[4]);

                    var renewMessageScope = _listener.AssertAndRemoveScope(DiagnosticProperty.RenewMessageLockActivityName);
                    AssertCommonTags(renewMessageScope.Activity, receiver.EntityPath, receiver.FullyQualifiedNamespace);
                }

                // schedule
                msgs = ServiceBusTestUtilities.GetMessages(numMessages, sessionId);

                foreach (var msg in msgs)
                {
                    var seq = await sender.ScheduleMessageAsync(msg, DateTimeOffset.UtcNow.AddMinutes(1));

                    Assert.IsNotNull(msg.ApplicationProperties[DiagnosticProperty.DiagnosticIdAttribute]);

                    var messageScope = _listener.AssertAndRemoveScope(DiagnosticProperty.MessageActivityName);
                    AssertCommonTags(messageScope.Activity, sender.EntityPath, sender.FullyQualifiedNamespace);

                    var scheduleScope = _listener.AssertAndRemoveScope(DiagnosticProperty.ScheduleActivityName);
                    AssertCommonTags(scheduleScope.Activity, sender.EntityPath, sender.FullyQualifiedNamespace);

                    var linkedActivities = scheduleScope.LinkedActivities;
                    Assert.AreEqual(1, linkedActivities.Count);
                    Assert.AreEqual(messageScope.Activity.Id, linkedActivities[0].ParentId);

                    await sender.CancelScheduledMessageAsync(seq);

                    var cancelScope = _listener.AssertAndRemoveScope(DiagnosticProperty.CancelActivityName);
                    AssertCommonTags(cancelScope.Activity, sender.EntityPath, sender.FullyQualifiedNamespace);
                }

                // send a batch
                var batch = await sender.CreateMessageBatchAsync();

                for (int i = 0; i < numMessages; i++)
                {
                    batch.TryAddMessage(ServiceBusTestUtilities.GetMessage(sessionId));
                }
                await sender.SendMessagesAsync(batch);

                AssertSendActivities(useSessions, sender, batch.AsReadOnly <ServiceBusMessage>());
            };
        }
Beispiel #22
0
        private async Task RunBatchReceiveLoopAsync(CancellationToken cancellationToken)
        {
            ServiceBusClient   sessionClient = null;
            ServiceBusReceiver receiver      = null;

            if (_isSessionsEnabled)
            {
                sessionClient = _client.Value;
            }
            else
            {
                receiver = _batchReceiver.Value;
            }

            while (true)
            {
                try
                {
                    if (cancellationToken.IsCancellationRequested)
                    {
                        _logger.LogInformation("Message processing has been stopped or cancelled");
                        return;
                    }

                    if (_isSessionsEnabled && (receiver == null || receiver.IsClosed))
                    {
                        try
                        {
                            receiver = await sessionClient.AcceptNextSessionAsync(
                                _entityPath,
                                new ServiceBusSessionReceiverOptions
                            {
                                PrefetchCount = _serviceBusOptions.PrefetchCount
                            },
                                cancellationToken).ConfigureAwait(false);
                        }
                        catch (ServiceBusException ex)
                            when(ex.Reason == ServiceBusFailureReason.ServiceTimeout)
                            {
                                // it's expected if the entity is empty, try next time
                                continue;
                            }
                    }

                    IReadOnlyList <ServiceBusReceivedMessage> messages =
                        await receiver.ReceiveMessagesAsync(
                            _serviceBusOptions.MaxMessageBatchSize,
                            cancellationToken : cancellationToken).AwaitWithCancellation(cancellationToken);

                    if (messages.Count > 0)
                    {
                        ServiceBusReceivedMessage[] messagesArray = messages.ToArray();
                        ServiceBusTriggerInput      input         = ServiceBusTriggerInput.CreateBatch(messagesArray);
                        if (_isSessionsEnabled)
                        {
                            input.MessageActions = new ServiceBusSessionMessageActions((ServiceBusSessionReceiver)receiver);
                        }
                        else
                        {
                            input.MessageActions = new ServiceBusMessageActions(receiver);
                        }
                        FunctionResult result = await _triggerExecutor.TryExecuteAsync(input.GetTriggerFunctionData(), cancellationToken).ConfigureAwait(false);

                        // Complete batch of messages only if the execution was successful
                        if (_autoCompleteMessagesOptionEvaluatedValue)
                        {
                            if (result.Succeeded)
                            {
                                List <Task> completeTasks = new List <Task>();
                                foreach (ServiceBusReceivedMessage message in messagesArray)
                                {
                                    // skip messages that were settled in the user's function
                                    if (input.MessageActions.SettledMessages.Contains(message))
                                    {
                                        continue;
                                    }

                                    // Pass CancellationToken.None to allow autocompletion to finish even when shutting down
                                    completeTasks.Add(receiver.CompleteMessageAsync(message, CancellationToken.None));
                                }

                                await Task.WhenAll(completeTasks).ConfigureAwait(false);
                            }
                            else
                            {
                                List <Task> abandonTasks = new List <Task>();
                                foreach (ServiceBusReceivedMessage message in messagesArray)
                                {
                                    // skip messages that were settled in the user's function
                                    if (input.MessageActions.SettledMessages.Contains(message))
                                    {
                                        continue;
                                    }

                                    // Pass CancellationToken.None to allow abandon to finish even when shutting down
                                    abandonTasks.Add(receiver.AbandonMessageAsync(message, cancellationToken: CancellationToken.None));
                                }

                                await Task.WhenAll(abandonTasks).ConfigureAwait(false);
                            }
                        }
                    }
                    else
                    {
                        // Close the session and release the session lock after draining all messages for the accepted session.
                        if (_isSessionsEnabled)
                        {
                            // Use CancellationToken.None to attempt to close the receiver even when shutting down
                            await receiver.CloseAsync(CancellationToken.None).ConfigureAwait(false);
                        }
                    }
                }
                catch (ObjectDisposedException)
                {
                    // Ignore as we are stopping the host
                }
                catch (OperationCanceledException)
                    when(cancellationToken.IsCancellationRequested)
                    {
                        // Ignore as we are stopping the host
                        _logger.LogInformation("Message processing has been stopped or cancelled");
                    }
                catch (Exception ex)
                {
                    // Log another exception
                    _logger.LogError(ex, $"An unhandled exception occurred in the message batch receive loop");

                    if (_isSessionsEnabled && receiver != null)
                    {
                        // Attempt to close the session and release session lock to accept a new session on the next loop iteration
                        try
                        {
                            // Use CancellationToken.None to attempt to close the receiver even when shutting down
                            await receiver.CloseAsync(CancellationToken.None).ConfigureAwait(false);
                        }
                        catch
                        {
                            // Best effort
                            receiver = null;
                        }
                    }
                }
            }
        }
        async Task <long> DoPurgeNonSessionEntity(long messagesToPurgeCount, bool purgeDeadLetterSubqueueInstead)
        {
            long totalMessagesPurged = 0;
            var  taskCount           = Math.Min((int)messagesToPurgeCount / 1000 + 1, 20);
            var  tasks = new Task[taskCount];
            var  quit  = false; // This instance controls all the receiving tasks

            var client = new ServiceBusClient(
                serviceBusHelper.ConnectionString,
                new ServiceBusClientOptions {
                TransportType = serviceBusHelper.TransportType
            });

            try
            {
                for (var taskIndex = 0; taskIndex < tasks.Length; taskIndex++)
                {
                    tasks[taskIndex] = Task.Run(async() =>
                    {
                        ServiceBusReceiver receiver = CreateServiceBusReceiver(
                            client,
                            purgeDeadLetterSubqueueInstead);

                        try
                        {
                            var consecutiveZeroBatchReceives  = 0;
                            const int enoughZeroBatchReceives = 3;

                            while (!quit && Interlocked.Read(ref totalMessagesPurged) < messagesToPurgeCount)
                            {
                                IEnumerable <ServiceBusReceivedMessage> messages;

                                messages = await receiver.ReceiveMessagesAsync(
                                    maxMessages: 1000,
                                    maxWaitTime: TimeSpan.FromMilliseconds(20000 * (consecutiveZeroBatchReceives + 1)))
                                           .ConfigureAwait(false);

                                // ReSharper disable once PossibleMultipleEnumeration
                                if (messages != null && messages.Any())
                                {
                                    // ReSharper disable once PossibleMultipleEnumeration
                                    long messageCount = messages.Count();
                                    Interlocked.Add(ref totalMessagesPurged, messageCount);
                                }
                                else
                                {
                                    ++consecutiveZeroBatchReceives;
                                    if (consecutiveZeroBatchReceives >= enoughZeroBatchReceives)
                                    {
                                        quit = true;
                                    }
                                }
                            }
                        }
                        finally
                        {
                            if (null != receiver)
                            {
                                await receiver.CloseAsync().ConfigureAwait(false);
                            }
                        }
                    });  // End of lambda
                }

                await Task.WhenAll(tasks).ConfigureAwait(false);
            }
            finally
            {
                await client.DisposeAsync().ConfigureAwait(false);
            }

            return(totalMessagesPurged);
        }
Beispiel #24
0
        public static async Task Run([TimerTrigger("0 */2 * * * *")] TimerInfo myTimer, ILogger log)
        {
            if (log == null)
            {
                throw new ArgumentNullException(nameof(log));
            }

            if (myTimer == null)
            {
                throw new ArgumentNullException(nameof(myTimer));
            }

            var startDateTime = DateTime.UtcNow;

            log.LogInformation($"C# Timer trigger function v3 executed at: {startDateTime}. Next occurrence on {myTimer.Schedule.GetNextOccurrence(startDateTime)}.");

            var validServiceBusMessages = new List <ServiceBusReceivedMessage>();
            var transcriptionHelper     = new StartTranscriptionHelper(log);

            log.LogInformation("Pulling messages from queue...");
            var messages = await ServiceBusReceiver.ReceiveMessagesAsync(StartTranscriptionEnvironmentVariables.MessagesPerFunctionExecution, TimeSpan.FromSeconds(MessageReceiveTimeoutInSeconds)).ConfigureAwait(false);

            if (messages == null || !messages.Any())
            {
                log.LogInformation($"Got no messages in this iteration.");
                return;
            }

            log.LogInformation($"Got {messages.Count} in this iteration.");
            foreach (var message in messages)
            {
                if (message.LockedUntil > DateTime.UtcNow.AddSeconds(5))
                {
                    try
                    {
                        if (transcriptionHelper.IsValidServiceBusMessage(message))
                        {
                            await ServiceBusReceiver.RenewMessageLockAsync(message).ConfigureAwait(false);

                            validServiceBusMessages.Add(message);
                        }
                        else
                        {
                            await ServiceBusReceiver.CompleteMessageAsync(message).ConfigureAwait(false);
                        }
                    }
                    catch (ServiceBusException ex) when(ex.Reason == ServiceBusFailureReason.MessageLockLost)
                    {
                        log.LogInformation($"Message lock expired for message. Ignore message in this iteration.");
                    }
                }
            }

            if (!validServiceBusMessages.Any())
            {
                log.LogInformation("No valid messages were found in this function execution.");
                return;
            }

            log.LogInformation($"Pulled {validServiceBusMessages.Count} valid messages from queue.");

            await transcriptionHelper.StartTranscriptionsAsync(validServiceBusMessages, ServiceBusReceiver, startDateTime).ConfigureAwait(false);
        }