创建一个 c# windows 服务来轮询数据库

Posted

技术标签:

【中文标题】创建一个 c# windows 服务来轮询数据库【英文标题】:Creating a c# windows service to poll a database 【发布时间】:2013-10-30 18:29:25 【问题描述】:

我想编写一个服务来轮询数据库并根据返回的数据执行操作。

我不确定最好的方法是什么,我可以找到一些关于它的博客和这个堆栈溢出问题Polling Service - C#。但是我担心它们都已经很老了,可能已经过时了。

任何人都可以就当前的建议或最佳实践(如果有的话)向我提供有关执行此类操作的建议,或向我指出有关此问题的最新博客文章的方向。据我所知,使用计时器或 tpl 任务是两种可能的方法。

如果仍然建议使用计时器,那么当服务停止时它们将如何工作,因为我打算让这些服务执行的操作可能需要 30 多分钟,这就是我说使用任务的原因,因为我可以使用任务取消令牌但是这些在取消时会抛出异常(如果我错了,请纠正我)并且我认为我并不真正想要这种行为(尽管如果您认为有理由我会想要这种行为,请纠正我)。

很抱歉,我可能在一个问题中问了很多问题,但我并不完全确定自己在问什么。

【问题讨论】:

我会先看看生产者-消费者模式。一个线程可以轮询和收集作业信息,然后将其传递给队列处理程序。 您将多久轮询一次数据库?这是服务将做的all吗?如果服务所做的只是不频繁地轮询数据库并且可能运行一个很长的任务,那么您最好编写一个普通的旧控制台应用程序并将其设置为 Windows 中的计划任务。 你有任何链接可以在代码 Grant 中实现吗?吉姆 - 我打算每 2 分钟轮询一次。是的,这就是服务的全部功能,但我可能会在以后添加额外的功能来监控在线提要。 @user2647347,我没有具体的链接,但是如果你搜索 producer-consumer c#,你会发现大量的参考实现。我将此模式用于必须随时间处理多个任务的 Windows 服务,并且效果很好。 【参考方案1】:

为此使用 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;
      
    
  

就像我说的,我通常使用专用线程/任务而不是计时器。我这样做是因为我的轮询间隔几乎从来都不是恒定的。如果检测到暂时性错误(如网络或服务器可用性问题),我通常会开始减慢轮询速度,这样我的日志文件就不会快速连续地一遍又一遍地填满相同的错误消息。

【讨论】:

我喜欢使用 WaitHandler 在这里它似乎将它自己借给了一个更清洁的机制,然后是一个专门的计时器。将来我将不得不使用它。谢谢布赖恩! 谢谢,我有类似的东西,但 !cancellation.WaitHandle.WaitOne(interval) 是我认为我缺少的。 我使用了这个模板,有时我的服务只是冻结,我需要杀死进程来停止它,没有任何异常,有什么想法吗?或者我可以检查什么? @kosnkov:我怀疑问题出在mainTask.Wait。如果是这种情况,那么您的 Poll 表现良好。它需要测试取消令牌并在收到信号时快速关闭。 在哪里设置轮询间隔以及 WaitAfterErrorInterval 和 WaitAfterSuccessInterval 是什么数据类型【参考方案2】:

您有几个选择。从本质上最简单的选项开始,您可以决定将您的应用程序创建为控制台应用程序,并将可执行文件作为 Windows 任务计划程序中的任务运行。您需要做的就是将您的可执行文件分配为在任务中启动的程序,并让任务调度程序为您处理时间间隔。如果您不关心状态,这可能是首选方式,并且如果您真的不需要,这将避免您不必担心创建和管理 Windows 服务。有关如何使用调度程序,请参阅以下链接。

Windows Task Scheduler

您可以这样做的下一个方法是创建一个 Windows 服务并在该服务中使用一个计时器,特别是 System.Timers.Timer。本质上,您可以将计时器间隔设置为您希望在运行流程之前经过的时间。然后,您将注册每次发生该间隔时都会触发的计时器滴答事件。在这种情况下,您基本上将拥有您想要运行的流程;如果您愿意,这可以启动附加线程。然后在初始设置之后,您只需调用计时器 Start() 函数或将 Enabled 属性设置为 True 即可启动计时器。可以在描述对象的 MSDN 页面上的示例中找到一个很好的示例。那里有很多教程展示了如何设置 Windows 服务,所以我不会专门介绍它。

MSDN: System.Timers.Timer

最后,更复杂的是设置一个侦听 SqlDependency 的 Windows 服务。如果事情可能发生在您的应用程序之外的数据库中,但您需要在您的应用程序或其他一些服务中意识到它,则此技术很有用。以下链接有一个关于如何在应用程序中设置 SqlDependency 的很好的教程。

Using SqlDependency To Monitor SQL Database Changes

我想从您的原始帖子中指出两点并非针对您的问题。

    如果您正在编写一个真正的 Windows 服务,您不希望该服务停止。服务应该持续运行,如果确实发生异常,应该适当处理,而不是停止服务。

    取消令牌不必抛出异常;简单地不调用 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);
        
    );  

【讨论】:

以上是关于创建一个 c# windows 服务来轮询数据库的主要内容,如果未能解决你的问题,请参考以下文章

显示窗口服务的弹出窗口

桌面窗口集合更改时调用异步委托?

检测 SQL Server 是不是正在运行

OOP COM 服务器更新客户端

Spring Integration - 并发服务激活器

以编程方式使用 Gmail 接收电子邮件?