Quantcast
Channel: Service Bus forum
Viewing all articles
Browse latest Browse all 1916

OnMessage and lock expired message with multiple consumers

$
0
0

Hi,

I'm venturing into this are and created a sample solution with 1 pulisher console app which adds to the queue, and 1 consumer which implements the OnMessage callback to recieve the items.

When i spin up multiple instances of the consumer console app i can see they are all picking up items from the queue but i get alot of "The lock supplied is invalid. Either the lock expired, or the message has already been removed from the queue" errors.

Sometimes i can see in the consumer console output that different consumers pick up the same message which i thought shouldnt be happening. In this case if 2 queues pick up the same item then try executing db calls/web service calls and so on. then one finishes, when the other tries to call CompleteAsync it'll throw exception because the item is already removed from the queue, but my logic has already been executed.

Any help/comments/suggestions are appreciated.

Here is the test code i'm using:

Publisher:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel.Description;
using System.Threading.Tasks;
using Microsoft.Azure;
using Microsoft.ServiceBus;
using Microsoft.ServiceBus.Messaging;

namespace QueuePublisher
{
    class Program
    {
        private static string connectionString;
        private static NamespaceManager namespaceManager;
        private static string queueName = "TestQueue";

        static void Main(string[] args)
        {
            try
            {
                InitializeAzureQueue();
                SendMessageToQueue();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
            Console.WriteLine("Press any key to exit...");
            Console.ReadKey();
        }

        public static void InitializeAzureQueue()
        {
            connectionString = CloudConfigurationManager.GetSetting("Microsoft.ServiceBus.ConnectionString");
            namespaceManager = NamespaceManager.CreateFromConnectionString(connectionString);
            CreateTestQueue(queueName);
        }

        public static void CreateTestQueue(string name)
        {
            QueueDescription qd = new QueueDescription(name)
            {
                MaxSizeInMegabytes = 5120,
                DefaultMessageTimeToLive = new TimeSpan(0, 1, 0),
                LockDuration = new TimeSpan(0, 5, 0)
            };

            if (!namespaceManager.QueueExists(name))
            {
                namespaceManager.CreateQueue(qd);
            }
        }


        public static void SendMessageToQueue()
        {
            var client = QueueClient.CreateFromConnectionString(connectionString, queueName);

        MessageCountDetails:
            Console.WriteLine("Please enter the number of messages to send:");

            var line = Console.ReadLine();
            if (line.ToLower() == "q") return;

            int value = 0;
            if (int.TryParse(line, out value))
            {
                Console.WriteLine("Creating {0} messages...", value);
            }
            else
            {
                goto MessageCountDetails;
            }

            var list = new List<BrokeredMessage>();

            for (int i = 1; i <= value; i++)
            {
                var message = new BrokeredMessage("Test message " + i);
                message.Properties["TestProperty"] = "TestValue";
                message.Properties["Message number"] = i;
                list.Add(message);
            }

            if (list.Any())
            {
                client.SendBatchAsync(list);
            }

            Console.WriteLine("{0} - Sent {1} messages to the {2} queue", DateTime.Now.ToString(), list.Count, queueName);
            goto MessageCountDetails;
        }
    }
}

Consumer:

using System;
using Microsoft.Azure;
using Microsoft.ServiceBus.Messaging;

namespace QueueConsumer
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                string connectionString = CloudConfigurationManager.GetSetting("Microsoft.ServiceBus.ConnectionString");
                QueueClient Client = QueueClient.CreateFromConnectionString(connectionString, "TestQueue");

                // Configure the callback options.
                OnMessageOptions options = new OnMessageOptions();
                options.AutoComplete = false;
                options.AutoRenewTimeout = TimeSpan.FromMinutes(1);

                Client.OnMessageAsync(async msg =>
                {
                    bool shouldAbandon = false;
                    try
                    {
                        Console.WriteLine("ThreadId: {0}, MessageId:{1}, Body{2}, TestProperty:{3}",
                           System.Threading.Thread.CurrentThread.ManagedThreadId,
                           msg.MessageId,
                           msg.GetBody<string>(),
                           msg.Properties["TestProperty"]);

                        //TODO: at this point do the message processing logic
                        // - eg. db calls, web service calls etc.

                        await msg.CompleteAsync();

                    }
                    catch (Exception ex)
                    {
                        shouldAbandon = true;
                        Console.WriteLine("ThreadId: {0}, Error: {1}", System.Threading.Thread.CurrentThread.ManagedThreadId, ex.Message);
                    }
                    finally
                    {
                        await msg.AbandonAsync();
                    }
                });

            }
            catch (Exception ex)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine(ex);
            }

            Console.ReadKey();
        }
    }
}




Viewing all articles
Browse latest Browse all 1916

Trending Articles