2015-06-26 111 views
1

我用來在Azure上使用webjob觸發Azure隊列。它像一個魅力。像WebJob隊列Azure WorkerRole觸發器

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是,直到被一個消息觸發的過程狀態並沒有完成,該消息是保持不可見(不刪除)。所以,如果關閉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 - 您無法自定義正在處理的消息的隱形超時。那麼輪詢隊列中的while(true),然後對這個參數有更好的控制呢? – DotNetMatt

0

如果不使用某種持久存儲來跟蹤您的工作進度,則可能無法解決此問題。如已經確定的那樣,您在作業開始之前刪除該消息,因此如果作業因任何原因(包括停止角色)失敗,則該消息將丟失。消息的最長鎖定時間爲5分鐘,這意味着在作業仍在運行時消息將再次重新出現,並且如果刪除操作已移至最後,則會由於丟失鎖定而失敗。

如果長時間運行的作業由多個較小的步驟組成,其中沒有一個超過5分鐘時間段,那麼您將能夠定期調用RenewLock()以保留消息的鎖定並阻止其重新出現在隊列。只要鎖永不過期,在這種情況下,最後的DeleteMessage將成功。這可能不太適合你的場景。

一個可能的解決方案是將作業狀態寫入Azure表,並在整個作業處理過程中記錄狀態。您的工作人員角色循環將檢查表中是否有尚未完成的作業,並繼續存在的任何作業,如果沒有找到,請檢查服務總線是否有任何新作業。這個解決方案也可能讓你有機會從他們到達的地方拿起失敗的工作,而不是從頭再次開始你的2小時工作。

+0

感謝您的回答,我喜歡您的nenewlock建議,但也許它可以像在webjob觸發器中一樣運行。但我不知道機械工程如何? – Julian50

相關問題