2013-10-30 34 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); 
     } 
    });