我想写一个服务,轮询一个数据库,并执行一个操作取决于数据被带回。
我不知道这样做的最好方法是什么,我可以find几个关于它的博客和这个堆栈溢出问题轮询服务 – C# 。 不过,我很警惕,他们都很老,可能过时了。
任何人都可以就目前的build议或最佳做法(如果有的话)就此做出build议,或者指向我最近的博客文章的方向。 从我能收集的任何一个计时器或tpl任务是这样做的两个潜在的方法。
如果定时器仍然被build议,那么当服务停止时它们将如何工作,因为我打算为这些服务执行的操作可能需要30分钟以上,这就是为什么我使用任务,因为我可以使用任务取消令牌,但是这些抛出当取消exception(如果我错了,纠正我),我不认为我真的想要这样的行为(虽然纠正我,如果你认为有一个原因,我会想这样做)。
对不起,我可能会问一个单一的问题很多,但我不完全确定我自己是什么问。
为此,请使用Windows服务。 使用计划任务本身并不是一个坏主意,但是既然你说民意测验每两分钟就能发生一次,那么你最好还是选择这个服务。 这项服务可以让你在民意调查之间维持一种状态,你也可以更好地控制民意调查的时间。 你说这个手术一旦启动就需要30多分钟的时间,所以也许你会推迟轮询,直到手术完成。 当逻辑作为服务运行时,这样做更容易一些。
最后,用什么机制来生成投票并不重要。 你可以使用一个定时器或一个专门的线程/任务睡觉或其他。 就个人而言,我发现专用的线程/任务比定时器更容易处理这些事情,因为更容易控制轮询间隔。 此外,您一定要使用第三方物流提供的协同取消机制。 没有必要抛出异常。 只有在您调用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; } } } }
就像我说的,我通常使用专用线程/任务而不是定时器。 我这样做是因为我的轮询时间间隔几乎不会保持不变。 如果检测到一个瞬间错误(如网络或服务器可用性问题),我通常会开始减慢轮询,这样我的日志文件就不会一次又一次地填满相同的错误消息。
你有几个选择。 要从本质上最简单的选项开始,您可以决定将您的应用程序创建为控制台应用程序,并将可执行文件作为Windows任务计划程序中的任务运行。 您需要做的就是将您的可执行文件分配为程序,以便在任务中启动,并让任务调度程序处理您的时间间隔。 如果你不关心状态,这可能是首选的方法,如果你不需要,可以防止你不必担心创建和管理Windows服务。 有关如何使用调度程序,请参阅以下链接。
Windows任务计划程序
接下来的方法是创建一个windows服务,并在该服务中使用一个定时器,特别是System.Timers.Timer 。 本质上,您可以在运行流程之前将计时器间隔设置为您想要通过的时间。 然后,您将注册计时器滴答事件,每发生一次间隔就会触发。 在这个事件中,你基本上有你想要运行的过程; 如果你愿意的话,这可以启动附加线程。 然后,在初始设置之后,您只需调用定时器Start()函数或将Enabled属性设置为True即可启动定时器。 在MSDN页面描述对象的例子中可以找到一个很好的例子。 有很多的教程,显示如何设置一个Windows服务,所以我不打扰到具体进入。
MSDN:System.Timers.Timer
最后也更复杂的是设置一个侦听SqlDependency的windows服务。 如果事情可能发生在应用程序之外的数据库中,但是您需要在应用程序或某些其他服务中使用该技术,则此技术非常有用。 下面的链接有一个关于如何在应用程序中设置SqlDependency的很好的教程。
使用SqlDependency监视SQL数据库更改
我想从你原来的帖子中指出的两件事情,并不是针对你的问题。
如果你正在写一个真正的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); } });