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))); } }
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>()); }
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); }
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()); } } }
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); } }
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}"); } } }
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); } }
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); }; }
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>()); }; }
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); }
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); }