2013-10-30 29 views
13

我想編寫一個民意調查數據庫,並根據所帶來的數據備份執行操作的服務。創建一個C#窗口服務輪詢數據庫

我不知道什麼是這樣做的最好的方式,我可以找到它,這個堆棧溢出問題Polling Service - C#幾個博客。不過,我很謹慎,他們都很古老,可能過時了。

誰能告訴我對目前的建議或最佳實踐(如果有的話)上做這樣的事情或點我在最近的博客文章這個方向。從我可以使用計時器或tpl任務可以收集的任務是執行此操作的兩種潛在方式。

如果仍然建議定時器,那麼當服務停止時它們將如何工作,因爲我打算讓這些服務執行的操作可能需要30分鐘以上,這就是爲什麼我說使用任務,因爲我可以使用任務取消但是這些在取消時會拋出異常(如果我錯了,請糾正我),並且我不認爲我真的想要這種行爲(儘管糾正了我,如果您認爲我有這樣的理由)。

對不起,我可能會問了很多在一個單一的問題,但我不能完全肯定自己是什麼我問。

+0

我會看看初學者的生產者 - 消費者模式。一個線程可以輪詢並收集工作信息,然後將其傳遞給隊列處理程序。 –

+0

您多長時間輪詢數據庫?這是服務將做的所有*嗎?如果所有服務都是不頻繁地輪詢數據庫並且可能運行一個很長的任務,那麼你可能最好是編寫一個普通的舊控制檯應用程序,並將其設置爲Windows中的計劃任務。 –

+0

您是否有任何鏈接可以在代碼Grant中實現? 吉姆 - 我計劃投票它也許有2分鐘。是的,這是所有服務都可以做到的,但我稍後也可能會添加額外的功能來監控在線提要。 – user2647347

回答

23

去同一個Windows服務這一點。使用計劃任務本身並不是一個壞主意,但既然你說民意調查可以每2分鐘發生一次,那麼你可能更願意使用該服務。該服務將允許您保持民意調查之間的狀態,並且您還可以更好地控制民意調查的時間。你說這項手術一旦啓動就需要30分鐘以上的時間,所以也許你會推遲輪詢,直到手術完成。當邏輯作爲服務運行時,這樣做更容易一些。

最後,用什麼機制來生成投票並不重要。你可以使用一個定時器或一個專門的線程/任務睡覺或任何。就個人而言,我發現專用線程/任務比定時器更容易處理這些事情,因爲它更容易控制輪詢間隔。此外,您一定要使用TPL提供的協作取消機制。它沒有必要拋出異常。它只有在您致電ThrowIfCancellationRequested時才這樣做。您可以使用IsCancellationRequested來檢查取消標記的狀態。

下面是一個非常通用的模板,您可以使用它開始。

public class YourService : ServiceBase 
{ 
    private CancellationTokenSource cts = new CancellationTokenSource(); 
    private Task mainTask = null; 

    protected override void OnStart(string[] args) 
    { 
    mainTask = new Task(Poll, cts.Token, TaskCreationOptions.LongRunning); 
    mainTask.Start(); 
    } 

    protected override void OnStop() 
    { 
    cts.Cancel(); 
    mainTask.Wait(); 
    } 

    private void Poll() 
    { 
    CancellationToken cancellation = cts.Token; 
    TimeSpan interval = TimeSpan.Zero; 
    while (!cancellation.WaitHandle.WaitOne(interval)) 
    { 
     try 
     { 
     // Put your code to poll here. 
     // Occasionally check the cancellation state. 
     if (cancellation.IsCancellationRequested) 
     { 
      break; 
     } 
     interval = WaitAfterSuccessInterval; 
     } 
     catch (Exception caught) 
     { 
     // Log the exception. 
     interval = WaitAfterErrorInterval; 
     } 
    } 
    } 
} 

就像我說的,我通常使用專用線程/任務而不是定時器。我這樣做是因爲我的輪詢間隔幾乎不會保持不變。如果檢測到瞬態錯誤(如網絡或服務器可用性問題),我通常會開始減慢投票速度,這樣我的日誌文件不會一次又一次地填滿相同的錯誤消息。

+0

我喜歡在這裏使用WaitHandler,它似乎把它自己借給了一個更乾淨的機制,然後是一個專門定時器。我將來不得不使用它。感謝Brian! –

+0

謝謝,我有類似的東西,但取消。WaitHandle.WaitOne(間隔)是我認爲我錯過了。 – user2647347

+0

我使用了這個模板,有時候我的服務器正在凍結,我需要終止進程,沒有任何異常,任何想法?或者我可以檢查什麼? – kosnkov

3

您有幾種選擇。要從本質上最簡單的選項開始,您可以決定將您的應用程序創建爲控制檯應用程序,並將可執行文件作爲Windows任務計劃程序中的任務運行。您只需將可執行文件分配爲程序即可開始執行任務,並讓任務計劃程序爲您處理計時間隔。如果你不關心狀態,這可能是首選的方法,並且如果你不需要,可以防止你不必擔心創建和管理Windows服務。有關如何使用調度程序,請參閱以下鏈接。

Windows Task Scheduler

你能做到這一點,接下來的方法是創建一個Windows服務,並在服務中使用的定時器,具體System.Timers.Timer。從本質上講,您可以在運行流程之前將計時器間隔設置爲您想要通過的時間。然後,您將註冊計時器滴答事件,每次發生該間隔時都會觸發。在這種情況下,你基本上有你想要運行的過程;如果你願意,這可以啓動附加線程。然後,在初始設置後,您只需調用定時器Start()函數或將Enabled屬性設置爲True即可啓動定時器。在MSDN頁面描述對象的例子中可以找到一個很好的例子。有很多教程顯示如何設置Windows服務,所以我不打算進入具體的。

MSDN: System.Timers.Timer

最後,更復雜的是設置一個偵聽的SqlDependency一個窗口服務。如果事情可能發生在應用程序之外的數據庫中,但您需要在應用程序或其他服務中使其知曉,則此技術非常有用。以下鏈接有關如何在應用程序中設置SqlDependency的很好的教程。

Using SqlDependency To Monitor SQL Database Changes


兩件事情,我想從你的原帖指出,並非專門針對你有問題。

  1. 如果您正在編寫真正的Windows服務,則不希望該服務停止。該服務應該不斷運行,如果出現異常,應該適當處理並且不要停止服務。

  2. 取消標記不必引發異常;只是不調用ThrowIfCancellationRequested()將導致異常不會被拋出,或者如果這是CancellationTokenSource,則在Cancel方法上將參數設置爲false,然後檢查該令牌以查看是否在線程中請求取消並優雅地返回線程如果是這樣。

例如:

CancellationTokenSource cts = new CancellationTokenSource(); 
    ParallelOptions options = new ParallelOptions 
    { 
     CancellationToken = cts.Token 
    }; 
    Parallel.ForEach(data, options, i => 
    { 
     try 
     { 
      if (cts.IsCancellationRequested) return; 

      //do stuff 

     } 
     catch (Exception ex) 
     { 
      cts.Cancel(false); 
     } 
    });