2015-06-26 3 views
1

Я использую webjob на Azure, запускающий очередь Azure. Отлично работает.Azure WorkerRole триггер в очереди, как WebJob

Azure tutorial webjob + queue

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

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

Что действительно хорошо с queueTrigger это пока процесс инициируется сообщением не IsNot сделано, сообщение держать невидимым (не удалять). Поэтому, если вы отключите webjob (например, для обновления webjob) Сообщение будет видно (после небольшого таймаута) в очереди, чтобы быть обработанным обновленным webjob (отлично).

Теперь я хочу сделать то же самое, но на роль рабочего. Сегодня мне это нравится.

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

Но если я остановлю рабочего во время работы, я потерял сообщение. Так как я могу сделать, как запуск webJob?

+0

Azure WebJobs SDK также работает в WorkerRole, поэтому вы можете использовать тот же код QueueTrigger. – mathewc

ответ

2

Наконец-то я нахожу простое решение. Перед выполнением моей работы в течение нескольких часов я запускаю задачу KeepHiddenMessageAsync, которая обновляет сообщение с таймаутом. Перед окончанием таймаута выполняется новое обновление сообщения. Если возникла проблема, тогда будет достигнут тайм-аут сообщения, и сообщение станет видимым.

 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); 
       } 
      } 
     } 
0

По умолчанию после получения сообщения о очереди оно становится невидимым в течение 5 минут. После этой задержки, если сообщение не было удалено из очереди, оно снова станет видимым, так что его можно будет обработать еще раз.

В своем примере кода вы удаляете сообщение, как только получаете его из очереди. Если вы хотите сделать это безопасным, сообщение должно быть удалено только в конце вашего процесса. Вы пытались переместить sourceImportationQueue.DeleteMessage(cloudMessage); в конце обработки?

+0

Я согласен с тобой НО;) как написано, работа занимает несколько часов (комментарий к коду), поэтому не могу перемещать Deltemessage в конце – Julian50

+0

А, да, я не обращал внимания на этот вопрос. Проблема при использовании атрибута QueueTrigger заключается в том, что - AFAIK - вы не можете настроить тайм-аут невидимости обрабатываемого сообщения.Итак, как насчет опроса очереди в то время (правда), а затем более эффективного контроля над этим параметром? – DotNetMatt

0

Возможно, не удастся решить эту проблему, не используя какое-то постоянное хранилище, чтобы отслеживать прогресс вашей работы. Как уже было указано, вы удаляете сообщение до того, как начнется ваше задание, поэтому, если задание не работает по какой-либо причине, включая остановку роли, сообщение теряется. Максимальный период блокировки для сообщения составляет 5 минут, что означает, что сообщение снова появится снова, пока ваше задание все еще запущено, и если операция удаления была перенесена в конец, она потерпит неудачу из-за потери блокировки.

Если ваша работа в течение длительного времени состоит из нескольких шагов меньшего размера, которые не превышают 5-минутный период, вы можете периодически звонить RenewLock(), чтобы сохранить блокировку сообщения и остановить его повторное появление на очередь. До тех пор, пока блокировка не закончится, DeleteMessage в конце будет успешным в этом случае. Вероятно, это вряд ли подходит для вашего сценария.

Возможным решением может быть запись статуса задания, например, в таблицу Azure и состояние записи во время обработки вашей работы. Ваш рабочий цикл роли будет проверять таблицу для любых заданий, которые еще не были завершены, и продолжать существовать, и если ни один не найден, проверьте служебную шину для любых новых заданий. Это решение также может дать вам возможность получить неудачные задания с того места, в котором они были достигнуты, вместо того, чтобы начать свою 2-часовую работу с самого начала.

+0

спасибо за ваш ответ, мне нравится ваше предложение о подключении, но, возможно, оно может работать как в триггере webjob. Но я не знаю, как работает механическое устройство? – Julian50