简体   繁体   English

像WebJob这样的队列上的Azure WorkerRole触发器

[英]Azure WorkerRole trigger on queue like WebJob

I'm used to use webjob on Azure triggering an Azure queue. 我曾经在Azure上使用webjob触发Azure队列。 It works like a charm. 它像一种魅力。

Azure tutorial webjob + queue Azure教程Webjob +队列

static void Main(string[] args)
{
    JobHost host = new JobHost();
    host.RunAndBlock();
}

public static void ProcessQueueMessage([QueueTrigger("logqueue")] string logMessage, TextWriter logger)
{
    logger.WriteLine(logMessage);
}

What's really good with queueTrigger is until the process triggered by a message isnot done, the message is keep invisible (not delete). queueTrigger的真正好处是直到消息触发的过程没有完成,消息保持不可见(不是删除)。 So If you turn off the webjob (for webjob update for example) The message will be visible (after a little timeout) in the queue to be process by the updated webjob (perfect). 因此,如果您关闭了Web作业(例如,用于Web作业更新),则该消息将在队列中可见(稍稍超时),由更新的Web作业处理(完美)。

Now I wanna do the same thing but on a worker role. 现在我想做同样的事情,但要担任工人角色。 Today I do like this. 今天我确实喜欢这样。

while (true)
{
     var cloudMessage = await sourceImportationQueue.GetMessageAsync();
     if (cloudMessage != null)
           sourceImportationQueue.DeleteMessage(cloudMessage);
      // process my job (few hours)
     else
           await Task.Delay(1000 * 5);
}

But if I stop the worker during is job, I lost the message. 但是,如果我在工作期间停止工作,我会丢失消息。 So how can I do like webJob triggering ? 那么我该如何喜欢webJob触发?

Finally I find a simple solution. 最后,我找到一个简单的解决方案。 Before running my job of several hours, I launch a task KeepHiddenMessageAsync that update the message with the timeout. 在运行几个小时的工作之前,我启动了一个任务KeepHiddenMessageAsync ,该任务KeepHiddenMessageAsync随着超时更新消息。 Before the end of the timeout a new update of the message is done. 在超时结束之前,将完成消息的新更新。 If an problem occur then the timeout of the message will be reached and the message will become visible. 如果出现问题,则消息将达到超时,并且消息将变为可见。

        private bool jobIsComplete;

        private void Run()
        {
             while (true)
            {
                 jobIsComplete = false;
                 //get the message
                 var cloudMessage = await queue.GetMessageAsync();

                 if (cloudMessage != null)
                        //run the task to keep the message until end of the job and worker role stopping for an update for example 
                       var keepHiddenMessageTask = KeepHiddenMessageAsync(cloudMessage);

                        //
                        // process my job (few hours)
                        //

                      jobIsComplete = true;
                      await keepHiddenMessageTask;
                      await _queue.DeleteMessageAsync(cloudMessage);
                 else
                       await Task.Delay(1000 * 5);
            }
        }

        private async Task KeepHiddenMessageAsync(CloudQueueMessage iCloudQueueMessage)
        {
            while (true)
            {
                //Update message and hidding during 5 new minutes
                await _queue.UpdateMessageAsync(iCloudQueueMessage, TimeSpan.FromMinutes(5), MessageUpdateFields.Visibility);

                //Wait 4 minutes
                for (int i = 0; i < 60 * 4; i++)
                {
                    if (JobIsComplete)
                        return;
                    else
                        await Task.Delay(1000);
                }
            }
        }

By default once a queue message has been retrieved it becomes invisible for 5 minutes. 默认情况下,一旦检索到队列消息,它将在5分钟内变为不可见状态。 After this delay, if the message has not been deleted from the queue it will become visible again so that it can be processed once again. 在此延迟之后,如果尚未从队列中删除该消息,则它将再次变为可见,以便可以再次对其进行处理。

In your code sample you are deleting the message as soon as you get it from the queue. 在代码示例中,您将从队列中获取消息后立即将其删除。 If you want to make it safe the message should only be deleted at the end of your process. 如果要确保安全,则仅应在过程结束时删除该消息。 Have you tried to move sourceImportationQueue.DeleteMessage(cloudMessage); 您是否尝试过移动sourceImportationQueue.DeleteMessage(cloudMessage); at the end of the processing job? 在处理工作结束时?

It may not be possible to solve this issue without using some kind of persistent storage to track your job progress. 如果不使用某种持久性存储来跟踪您的工作进度,则可能无法解决此问题。 As already identified you are deleting the message before your job begins so if the the job fails for any reason, including stopping the role, the message is lost. 正如已经确定的那样,您正在作业开始之前删除该消息,因此,如果该作业由于任何原因(包括停止角色)而失败,则该消息将丢失。 The maximum lock period for a message is 5 minutes meaning that the message will re-appear again while your job is still running and if the delete operation was moved to the end it would fail due to having lost the lock. 一条消息的最大锁定时间为5分钟,这意味着该消息将在您的作业仍在运行时再次出现,并且如果删除操作移至末尾,则由于丢失了锁定而将失败。

If your long running job is comprised of multiple smaller steps none of which exceed the 5 minute period then you would be able to call RenewLock() periodically to retain the lock on the message and stop it from re-appearing on the queue. 如果您的长期任务由多个较小的步骤组成,且每个步骤均不超过5分钟,则您可以定期调用RenewLock()来保持对消息的锁定并阻止其再次出现在队列中。 As long as the lock never expires a DeleteMessage at the end would succeed in this case. 只要锁永不过期,在这种情况下,最后的DeleteMessage就会成功。 It's probably unlikely that this fits your scenario though. 不过,这不太可能适合您的情况。

A possible solution would be to write the job status to, for example, an Azure table and record state throughout the processing of your job. 一种可能的解决方案是将作业状态写入例如Azure表,并在整个作业处理过程中记录状态。 Your worker role loop would be to check the table for any jobs not yet completed and continue any that exist and if none found check the service bus for any new jobs. 您的工作人员角色循环将是检查表中是否有尚未完成的作业,然后继续执行所有存在的作业,如果找不到任何作业,请检查服务总线上是否有任何新作业。 This solution may also give you the chance to pick up failed jobs from the point they reached rather than starting your 2 hour job from the beginning again. 此解决方案还可能使您有机会从失败的那一刻开始选择失败的工作,而不是从头开始重新开始2个小时的工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM