2012-06-07 301 views
6

可以通過WebRole.cs OnStart()方法運行線程,以便我們可以通過aspx頁面訪問它以執行後臺工作? 我知道正確的做法是使用工人角色,但我希望儘可能降低運行成本。Azure Web角色中的後臺線程

這個想法是創建一個線程,總是會運行並等待工作,例如,如果我想進行阻塞操作就像發送電子郵件我會使用線程給出SendEmail方法,是否有可能去做?如果是這樣,你能否給我提供一些可以指引我正確方向的例子?

+0

這將如何降低運行成本?你想要什麼不同於單實例單一併發服務? – Paparazzi

+3

@Blam - 在Web角色中運行後臺任務允許將操作組合成一組VM實例。這與將背景操作放在單獨的一組角色實例中形成鮮明對比。組合成一個角色將節省成本,因爲每個角色必須至少有一個實例正在運行。對於小批量網站,這是一個非常節省成本的架構。如果存在背景任務捱餓網站的風險,或者需要分別縮放前端和後臺任務(或者需要不同的VM大小),則值得考慮轉向單獨的角色。 –

+0

@DavidMakogon謝謝我不知道一個工作者角色需要一個單獨的實例。我沒有試圖回答這個問題。 +1我從這個問題中學到了很多東西。 – Paparazzi

回答

10

我會suggets一個解決方案,是從萊昂和大衛的解決方案不同:

  • 大衛的解決方案是確定的,但不是彈性的。實例/進程在處理任務時脫機了什麼?
  • Leon的解決方案大多適用於預定作業,但發送電子郵件並不總是按計劃安排的(也許您想在有人在您的應用程序中註冊時發送電子郵件)。

的另一種選擇,你應該看看使用的是Windows Azure存儲隊列(他們很便宜)在這種情況下:

  • Web應用程序:將消息發送到隊列(如「發送電子郵件to [email protected]')
  • WebRole.cs:在啓動實例時產生一個新線程,讓它偵聽來自該隊列的消息。每當消息到達時,處理它。如果成功,則從隊列中刪除消息。

該解決方案有很多優點。 WebRole.cs運行在與Web應用程序不同的進程中,因此對請求線程沒有影響。除此之外,如果發送郵件因任何原因失敗,郵件將保留在隊列中並在下次處理。如果應用程序或進程崩潰,這將確保您不會丟失任何要執行的任務。

下面是一個讓你開始的例子。請注意,如果您希望生產準備就緒(重試策略,異常處理,退避輪詢等),則需要改進此代碼:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using Microsoft.WindowsAzure; 
using Microsoft.WindowsAzure.Diagnostics; 
using Microsoft.WindowsAzure.ServiceRuntime; 
using Microsoft.WindowsAzure.StorageClient; 
using System.Threading.Tasks; 

namespace MvcWebRole1 
{ 
    public class WebRole : RoleEntryPoint 
    { 
     public override bool OnStart() 
     { 
      Task.Factory.StartNew(InitializeQueueListener); 
      return base.OnStart(); 
     } 

     private void InitializeQueueListener() 
     { 
      Microsoft.WindowsAzure.CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) => 
      { 
       configSetter(Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment.GetConfigurationSettingValue(configName)); 
      }); 


      var storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString"); 
      var queueStorage = storageAccount.CreateCloudQueueClient(); 
      var queue = queueStorage.GetQueueReference("myqueue"); 
      queue.CreateIfNotExist(); 

      while (true) 
      { 
       CloudQueueMessage msg = queue.GetMessage(); 
       if (msg != null) 
       { 
        // DO SOMETHING HERE 
        queue.DeleteMessage(msg); 
       } 
       else 
       { 
        System.Threading.Thread.Sleep(1000); 
       } 
      } 
     } 
    } 
} 
+0

似乎是更好的解決方案,我願意執行的工作類型,無論如何,我打算讓隊列與內部應用程序「交談」,所以它不會那麼昂貴......您可以進一步詳細瞭解「在啓動實例時產生一個新的線程並讓它監聽來自該隊列的消息」? **如果你可以給我一個例子,或者指向一個樣例,它解釋了在WebRole.cs **中啓動一個監聽線程所涉及的線程部分,那將是非常好的。謝謝 – ToinoBiclas

+0

同意 - 隊列非常有彈性。我的意圖是指出創建線程的可行性(這並不總是顯而易見的)。 –

+0

@Sandrino讓我知道如果這是內聯與您的解決方案...在WebRole.OnStart()'新線程(新ThreadStart(ClassListeningToQueue.Method0)''創建一個線程'然後在Method0內寫入一個無限循環或條件循環它只通過WebRole.OnStop()'while(true){try {CloudQueueMessage msg = queue.GetMessage(); if(msg!= null){''finnaly根據msg中的值執行任務,例如我可以有一個字段指出調用的方法和參數,在主線程中調用其他線程是否安全? – ToinoBiclas

1

我發現這個時候我一直在尋找的「蔚藍計劃任務」:http://www.ronaldwidha.net/2011/02/23/cron-job-on-azure-using-scheduled-task-on-a-web-role-to-replace-azure-worker-role-for-background-job/

看起來正是你要尋找的。

+0

您指出的例子是用於運行預定作業,很像Linux中的crontabs。我願意做一個等待被髮信號的線程。 – ToinoBiclas

+0

這只是指出,完全可以做這些事情。我想你可以用一點創意想出一個解決方案。 –

2

絕對可以創建一個線程(或很多)。 Web角色基本上是Windows 2008 Server。您不需要單獨的工作人員角色來設置後臺任務。當然,你的可以有一個單獨的輔助角色,這將允許你擴展這些實例,而不依賴於你的Web角色實例。這是您需要平衡性能/擴展與成本之間的關係。

+0

你能給我一些關於如何做到這一點的細節?如果我已經在WebRole:RoleEntryPoint中聲明瞭,我怎樣才能從一個aspx網頁訪問線程變量? – ToinoBiclas

+2

如果您需要與aspx頁面中的線程交互,爲什麼不從global.asax啓動線程? RoleEntryPoint將在單獨的AppDomain中運行,因此您不會在應用程序和線程之間進行交互。 –

+0

老實說從未想過這件事。我將嘗試使用global.asax中聲明的線程池進行一些測試。 – ToinoBiclas