Implementing Delay Queue using one or more standard FIFO Queues [closed]

女生的网名这么多〃 提交于 2021-01-27 18:41:05

问题


A delay queue is a queue in which each message has a delay time associated with it and a message can only be taken when its delay has expired. The head of the queue is that message whose delay expired furthest in the past. If no delay has expired there is no head and dequeue will return null.

Actually, I am writing a cloud application using Azure and in Azure only FIFO queues are available and not priority/delay queues. So I came here looking if someone can give me some pointers from where I can head start in the right direction. I googled a lot but only find out about the delay queues implementation in Java and no standard tutorial/research paper which talks about delay queues in general.

EDIT:

What I have code?
Actually, I have to first design this things and present it to my manager and once we finalize the design then only I can start coding.

More details about the scenario
Its a distributed application based on master/slave model. A master produce messages and put them into Azure Service Bus queues and there are multiple slaves (running on multiple machines) which read from queues and precess them. If in case a master goes down, then one of the slave acts as a master and starts producing messages. I don't want to store any state information in the master because in case master goes down all that state information will also goes with it.


回答1:


Windows Azure Queue messages have a delay, in seconds, that you specify when inserting a message onto the queue. A message won't be visible until that timeout delay is hit. See this MSDN article to see the API details.

The invisibility timeout is implemented in the various language SDK implementations as well. Since you're working with C#, here's what the AddMessage() call would look like. Note the 3rd parameter of AddMessage()specifies the invisibility timeout:

        var acct = CloudStorageAccount.DevelopmentStorageAccount;
        var queueClient = acct.CreateCloudQueueClient();
        var queue = queueClient.GetQueueReference("myqueue");
        queue.CreateIfNotExist();

        var msg = new CloudQueueMessage("test message");
        queue.AddMessage(msg, TimeSpan.FromHours(2), TimeSpan.FromMinutes(30));



回答2:


So to start with we'll need an implementation of a Priority Queue. Here's one I wrote a short while ago. It's probably not ideal; it has a tiny API, and it could probably perform better, but it's a sufficient starting place:

public class PriorityQueue<TPriority, TElement>
{
    SortedDictionary<TPriority, Queue<TElement>> dictionary = new SortedDictionary<TPriority, Queue<TElement>>();
    public PriorityQueue()
    {
    }

    public Tuple<TPriority, TElement> Peek()
    {
        var firstPair = dictionary.First();
        return Tuple.Create(firstPair.Key, firstPair.Value.First());
    }

    public TElement Pop()
    {
        var firstPair = dictionary.First();
        TElement output = firstPair.Value.Dequeue();

        if (!firstPair.Value.Any())
            dictionary.Remove(firstPair.Key);

        return output;
    }

    public void Push(TPriority priority, TElement element)
    {
        Queue<TElement> queue;
        if (dictionary.TryGetValue(priority, out queue))
        {
            queue.Enqueue(element);
        }
        else
        {
            var newQueue = new Queue<TElement>();
            newQueue.Enqueue(element);
            dictionary.Add(priority, newQueue);
        }
    }
}

A delay queue is simple enough when wrapping that:

public class DelayQueue<T>
{
    private PriorityQueue<DateTime, T> queue = new PriorityQueue<DateTime, T>();
    public void Enqueue(T item, int delay)
    {
        queue.Push(DateTime.Now.AddMilliseconds(delay), item);
    }

    public T Dequeue()
    {
        if (queue.Peek().Item1 > DateTime.Now)
            return queue.Pop();
        else
            return default(T);
    }
}



回答3:


How about you build a queue with a two-step process to dequeue items. Here is the high level process:

  • Dequeue the first item in the FIFO queue; set its invisibility to N minutes (whatever you decide the invisibility should be) - this allows you to make the item invisible for a period of time, as if it didn't exist in the queue. Here is the NextVisibleTime property I am referring to.

  • Check the DequeueCount property - if the dequeue count is 0, it was the first time this item was dequeded. Ignore the item and move on. Since its invisibility was set, it won't be fetched again until it's time. If the dequeue count is 1 or greater, it was dequeued once and must have been set invisible for the desired amount of time.

This should allow you to implement a delayed queue. I can think of other methods as well. For example each item in the queue as a Creation Time; this can be used to calculate dynamically how long an item needs to remain invisible. To change the invisibility of a property, check this method: http://msdn.microsoft.com/en-us/library/microsoft.windowsazure.storageclient.cloudqueue.updatemessage.aspx



来源:https://stackoverflow.com/questions/14159803/implementing-delay-queue-using-one-or-more-standard-fifo-queues

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!