Sends all messages with the same sessionId to the dead letter queue on Azure Service Bus Queue - azure

I am working with an azure service bus queue configured to be FIFO (First input first output). I work on an order application with the following states "Pending", "Received" and "Sent". therefore I have grouped the messages by the "SessionId" service bus option, setting the orderId as sessionId so that it processes the messages in order in case of horizontal scaling.
So far it works perfectly, the problem I have found is when a message in "pending" or "Received" status fails due to a timeout and goes to the dead letter queue. The message in "sent" status is processed correctly and then when the support team re-sends the "Pending" or "Received" status message to the queue it is processed correctly marking the order in a previous status instead of "sent" ".
I can think of several ways to control this, for example that the support team looks at the status of the order before reprocessing the message from the dead letter queue :) but I would like to know if service bus offers the possibility that if there is a message in the dead letter queu all the messages in the session queue that have the same sessionId go to the dead letter queu. Finallly, my question is:
Is there a way to configure azure service bus so that if there are any messages in the dead letter queue it sends all messages with the same sessionId to the dead letter queue?
Thank you very much!!!

I would like to know if service bus offers the possibility that if there is a message in the dead letter queue all the messages in the session queue that have the same sessionId go to the dead letter queue.
No, there is no such offering by Service Bus by default.
Is there a way to configure azure service bus so that if there are any messages in the dead letter queue it sends all messages with the same sessionId to the dead letter queue?
Yes, you can do that. You can first peek the messages in your dead-letter queue to fetch all the session ids. Then you can receive the messages in your main queue whose session id is in the DLQ, and then move those messages to DLQ. Here's one such logic I've implemented in dot net using the latest version of Service Bus SDK.
var queueName = "<queue>";
var connectionString = "<connection-string>";
var client = new ServiceBusClient(connectionString);
var sessionIdInDLQList = new List<string>();
var receiver = client.CreateReceiver(queueName, new ServiceBusReceiverOptions { SubQueue = SubQueue.DeadLetter });
var message = await receiver.PeekMessageAsync();
while (message != null)
{
if (!sessionIdInDLQList.Contains(message.SessionId))
sessionIdInDLQList.Add(message.SessionId);
message = await receiver.PeekMessageAsync();
}
foreach (var sessionId in sessionIdInDLQList)
{
var session = await client.AcceptSessionAsync(queueName, sessionId);
message = await session.ReceiveMessageAsync(TimeSpan.FromSeconds(20));
while (message != null)
{
await session.DeadLetterMessageAsync(message, "Message with this session is to be dead-lettered!");
message = await session.ReceiveMessageAsync(TimeSpan.FromSeconds(20));
}
}
In your case, you need to do this before your consumers start reading the messages, probably you can write this in your consumer application or any trigger application like Azure Function or worker role. That’s upto your method of handling.

You can try this code to read Dead Letter from Queue.
public static async Task GetMessage()
{
string topic = "myqueue1";
string connectionString = "Endpoint = sb://xxx.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=xxx";
var servicebusclient = new ServiceBusClient(connectionString);
var reciveroptions = new ServiceBusReceiverOptions { SubQueue = SubQueue.DeadLetter };
var reciver = servicebusclient.CreateReceiver(topic, reciveroptions);
// 10 number of message read from Queue
await receiver.PeekMessageAsync(10);
}
after receiving message from Dead Letter you can send to queue.
As per Microsoft official documents
There's no automatic cleanup of the DLQ. Messages remain in the DLQ
until you explicitly retrieve them from the DLQ and call Complete() on
the dead-letter message.
These following document help you.
Thanks Casually Coding for posting post on Read Message from the Dead Letter Queue
Microsoft Documents Using Dead-Letter Queues to Handle Message Transfer Failures , Receive Message from Dead letter queue

Related

Azure Service Bus Process Schedule Message before the schedule time

I have an API that will call Azure Topic to schedule a message. Is there a way to receive that message before the schedule time? For example in my code below, I schedule a message to azure topic and it will be queue after 60mins/1hr. Is there a way to received that message before 1hr?
string queueName = "topic";
var client = new ServiceBusClient("", new ServiceBusClientOptions()
{
TransportType = ServiceBusTransportType.AmqpWebSockets
});
// create the sender
ServiceBusSender sender = client.CreateSender(queueName);
// create a message that we can send. UTF-8 encoding is used when providing a string.
ServiceBusMessage message = new ServiceBusMessage($"Hello world cancel 13 {DateTime.Now}");
// add 5 minutes delay
long seq = await sender.ScheduleMessageAsync(message,
DateTimeOffset.Now.AddMinutes(60)
);
The message sequence number you get back when scheduling is suitable for cancelling but doesn't allow receiving that message earlier. The service doesn't allow early receiving, as anything that gets the messages to get the active messages (not in the future). For this scenario, I would suggest keeping the data in a database and not leveraging the queue as the database.

Microsoft.Azure.ServiceBus.MessagingEntityDisabledException: ReceiveDisabled

I have changed the Azure Service Bus Queue status from Active to ReceiveDisabled. Because I don’t want to process whenever message available in the queue. i.e. reason I have changed status to ReceiveDisabled.
After I changed the queue status to ReceiveDisabled, then I’m not able to post any message to that queue because I’m getting the below error.
Microsoft.Azure.ServiceBus.MessagingEntityDisabledException: Messaging entity 'sb://xxx-xxx-xxx.servicebus.windows.net/test-queue' is currently disabled
.Net Core code to change the queue status:
var serviceBusManagementClient = new ManagementClient(_serviceBusSettings.Connection);
foreach (var queueItem in queueItems)
{
var queueDescription = await serviceBusManagementClient.GetQueueAsync(queueItem.Value);
queueDescription.Status = EntityStatus.ReceiveDisabled;
await serviceBusManagementClient.UpdateQueueAsync(queueDescription);
}
.Net Core code to post messages to queue.
var messageSender = new MessageSender(serviceBusSettings.Connection, serviceBusSettings.MainQueueName);
var message = new Message(Encoding.UTF8.GetBytes(id))
{
//Assign a SessionId for the message
MessageId = id
};
// Send a message corresponding to this sessionId to the queue
messageSender.SendAsync(message);
I’m using the below references.
Microsoft.Azure.ServiceBus
Microsoft.Azure.ServiceBus.Management
Reference documentation https://learn.microsoft.com/en-us/azure/service-bus-messaging/entity-suspend
So, how can I post messages to Queue which is having ReceiveDisabled status?

Receiving Message Multiple times for a client and Message Deletes after one client received

I have two clients listening to a subscription of topic . I am seeing following issues.
Issue 1:
If one client receives a message and marks them completes other client won't receive that messages.
But i want all my clients to receive that message and acknowledge it so that once a client receives the message it shouldn't receive again
Issue 2:
If i don't acknowledge the message as complete . Some times i am receiving the message multiple times.
Issue 3:
During the Message Receive if see the Network disconnect. After some time it reconnects I am receiving the messages from starting again.
For Sending the Message Code
============
if (!namespaceManager.TopicExists("DataCollectionTopic"))
namespaceManager.CreateTopic("DataCollectionTopic");
if (!namespaceManager.SubscriptionExists("DataCollectionTopic", "one"))
namespaceManager.CreateSubscription("DataCollectionTopic", "one");
for(int i=0;i<100;i++)
{
BrokeredMessage bm = new BrokeredMessage("new Topic one");
bm.Label = "hELLLOOOO xcvxvxcvxvxvxc DummyMEssage"+i;
bm.Properties["StoreName"] = "asdasdasqwedas";
bm.Properties["MachineID"] = "Bajjiiiqweq567567wii";
if (namespaceManager == null)
{
Console.WriteLine("\nUnexpected Error");
return;
}
MessageSender sender = messageFactory.CreateMessageSender("DataCollectionTopic");
sender.Send(bm);
for receiving the message
===================
MessageReceiver receiver = await messageFactory.CreateMessageReceiverAsync("DataCollectionTopic/subscriptions/Vijay");
while (true) {
BrokeredMessage receivedMessage = receiver.Receive();
try
{
ProcessMessage(receivedMessage);
// receivedMessage.Complete();
}
catch (Exception e)
{
// receivedMessage.Abandon();
}
}
}
===============
TIA
Issue 1
If both clients receive using the same subscription name, they act as competing consumers. The first consumer to get the message and mark it as completed (processed) will be the winner. The rest of the clients won't process the same message. If intention is to receive a message (event) by all clients, then each client should have its own subscription and a copy of the message will be delivered to each subscription.
Issue 2
That is an expected behaviour. You receive the message up to MaxDeliverCount and after that message will be DLQ-ed. This is a default behaviour for PeekLock mode. With ReceiveAndDelete this doesn't happen, but it's a dangerous mode as you will lose the message if not processed successfully.
Issue 3
That is an expected behaviour. Each received message in a PeekLock mode has a LockDuration, time given to a processing code to complete the message or abandon it. If not completed, message becomes visible to other competing consumers and will be reprocessed up to DeliveryCount times.
To sum it up
Have multiple subscriptions per client for all of the clients to receive the same message (event)
Complete messages if done processing successfully. If you need time extension, renew the lock.

Receive only the last message on topics

I have an application subscribed on Azure Servicebus Topic who is constantly receiving messages from Stream Analytics. But this application isn't every time subscribed on this Topic. How do I receive only the last message from the topic when the application do the subscription?
Based on your question and your comments, this is what I can advice you:
When your application starts, connect to the Azure ServiceBus Subscription and get all messages in the queue.
Remove all the previous messages (just complete it) and process the last message.
Then you can start listening to new incoming messages.
Based on this answer (Clearing azure service bus queue in one go) :
// Get the message receiver
var messagingFactory = MessagingFactory.CreateFromConnectionString("ServiceBusConnectionString");
var messageReceiver = messagingFactory.CreateMessageReceiver(SubscriptionClient.FormatSubscriptionPath("TopicName", "SubscriptionName"));
BrokeredMessage lastMessage = null;
while (messageReceiver.Peek() != null)
{
if(lastMessage != null)
{
// This was not the last message so complete it.
lastMessage.Complete();
}
// Batch the receive operation
var brokeredMessages = messageReceiver.ReceiveBatch(300).ToList();
//Get the last message and remove it from the list
lastMessage = brokeredMessages.Last();
brokeredMessages.RemoveAt(brokeredMessages.Count -1);
// Complete all the other messages
var completeTasks = brokeredMessages.Select(m => Task.Run(() => m.Complete())).ToArray();
// Wait for the tasks to complete.
Task.WaitAll(completeTasks);
}
if (lastMessage != null)
{
// Process your message
}
// Start listening to new incoming message
messageReceiver.OnMessage(message =>
{
// Process new messages
}, new OnMessageOptions());

Azure: circular (ring) queue with unique key

For my app I need to organize a circular (ring) queue. It means that any processed message immediately goes to the end of the queue for continuous processing.
For example:
Queue: A, B, C.
Receiver processes A.
Queue: B, C, A.
2 and 3 should be performed atomically. So we never lose A or any other message.
Another requirement is to ignore duplicates. So there should be always a single A in the queue. Even if a sender pushes another A item. A refers to some unique (primary) key of the message here.
I looked for using Azure Service Bus, but I cannot find how to meet both requirements with it. Is it possible to implement the scenario with Service Bus? If not, what are best alternatives?
This kind of queue can be implemented with Service Bus sessions. Sessions provide "group by" mechanics, so we can assign our unique key to SessionId of the message and then receive messages in groups ignoring all messages in a group except the first one.
Implementation
1) Create a queue with RequiresSession set to true:
var queueDescription = new QueueDescription("CircularQueue")
{
RequiresSession = true,
};
await namespaceManager.CreateQueueAsync(queueDescription);
2) When sending message to the queue, set SessionId to your unique key value:
var message = new BrokeredMessage($"Message body")
{
MessageId = "MESSAGE_UNIQUE_KEY",
SessionId = "MESSAGE_UNIQUE_KEY"
};
await queueClient.SendAsync(message);
3) Receive messages using sessions:
while (true)
{
var session = await queueClient.AcceptMessageSessionAsync(TimeSpan.FromSeconds(10));
if (session == null)
continue;
try
{
var messages = (await session.ReceiveBatchAsync(100)).ToList();
if (messages.Count == 0)
continue;
var message = messages[0];
ProcessMessage(message);
await queueClient.SendAsync(message.Clone());
await session.CompleteBatchAsync(messages.Select(msg => msg.LockToken));
}
finally
{
await session.CloseAsync();
}
}
Based on the little I know about Azure Service Bus, I believe both of these requirements can be fulfilled with it individually, though I am not sure how both of them can be fulfilled together.
Message Cycling
It is my understanding that Azure Service Bus supports First-In-First-Out (FIFO) behavior. What you could do is fetch the message (say A) from the top of the queue in Receive and Delete mode and then reinsert the message back in the queue. Since you're creating a new message, it will be posted to the end of the queue.
Avoid Duplicate Messages
Service Bus Queues has a boolean property called RequiresDuplicateDetection and setting this value accordingly will prevent duplicate messages being inserted. A simple search for Azure Service Bus Duplicate Detection will lead you to many examples.

Resources