优雅地推迟QueueTrigger

时间:2014-11-25 17:21:53

标签: multithreading azure azure-webjobssdk

我目前正在使用WebJobs SDK来使用队列中发出的消息。

我的方法作为一个参数与[Microsoft.Azure.WebJobs.QueueTrigger(...)]属性一起被触发好了。 在某些情况下,该方法可以处理消息,但有时,我希望它拒绝消息,直到关键资源可用。

我试图在这种情况下抛出异常,但与引用所说的相反,队列触发器会立即再次触发(显然没有等待租用时间)。

有没有办法优雅地推迟邮件处理? 冻结线程等待关键资源是否安全?

任何提示都会非常感激。

3 个答案:

答案 0 :(得分:1)

我认为您不能在当前版本中推迟发送消息。

可能的解决方法

您可以延迟重新添加相同的邮件,为避免重复,您可以将MaxDequeueCount设置为1,这会将失败的邮件直接发送到异常后的队列队列:

        JobHostConfiguration configuration = new JobHostConfiguration();
        configuration.Queues.MaxDequeueCount = 1;

和消息处理器 - 重新添加延迟消息并抛出异常:

    public static void ProcessMessage([QueueTrigger("resource-heavy-queue")] string message, [Queue("resource-heavy-queue")]  CloudQueue originalQueue)
    {
        if ( /*Resource unavaliable*/)
        {
            var messageToReAdd = new CloudQueueMessage(message);
            originalQueue.AddMessage(messageToReAdd, null, TimeSpan.FromSeconds(10));
            throw new ResourcesNotAvailableException();
        }
    }

这样您就可以为您的资源实施某种退避策略。不幸的是,你必须手动处理一些问题:

  • 处理有害消息 - 如果您不断重新添加相同的消息,则最终会无限循环,因此您必须扩展消息模型以携带NumberOfRetries并在每次重新添加时将其递增< / LI>
  • 每次重新添加后,消息IdInsertionTime会有所不同,因此您无法依赖它们。

答案 1 :(得分:0)

抱歉,无法推迟触发器。你想要的是Azure WebJobs SDK没有的多重触发器(当消息和资源可用时触发)

有一些解决方法。如果该队列中的所有消息需要关键资源,您可以冻结该线程 - 您正在实现信号量 - 否则,调度变得棘手,因为如果达到最大数量,SDK将不会处理新消息并行运行的函数。

我会做什么而不是触发队列消息是关键资源上的触发器。当资源可用时,它会将消息放入另一个队列中,然后检查是否有任何要处理的消息需要该资源。

答案 2 :(得分:0)

我在这种情况下所做的是为同一个队列设置一个public static async Task HandleMessagesAsync([ServiceBusTrigger("%QueueName%")] BrokeredMessage message, [ServiceBus("%QueueName%")]ICollector<BrokeredMessage> queue, TextWriter logger) 我是从

触发的
%QueueName%

if (needToWait) { var delayedMessage = new BrokeredMessage(originalMessageBody) { Label = originalLabel, MessageId = originalMessageId, ScheduledEnqueueTimeUtc = DateTime.UtcNow + this.ExecutionDelay }; queue.Add(delayedMessage); return; } 表示法使SDK从app.config获取值

然后在处理程序中我正在做类似

的事情
{{1}}

这样当前消息就完成了,但是在定义的超时后,计划发送一个具有相同属性的新消息。

制作此程序时没有阻止任何线程。