需要:
招聘:
背景:
重点:
ego6inou1#
假设您正在处理数据库队列,由于数据库的事务性,您已经完成了相当一部分工作。典型的队列驱动应用程序具有一个循环,该循环执行以下操作:
while(1) { Start transction; Dequeue item from queue; process item; save new state of item; commit; }
如果处理中途崩溃,事务将回滚,并在下一次服务启动时处理该项。但是在数据库中编写队列实际上比你想象的要复杂很多。如果你使用一种幼稚的方法,你会发现你的入队和出队互相阻塞,ashx页面变得没有响应。接下来你会发现出队和出队死锁,你的循环经常遇到错误1205。我强烈建议你阅读这篇文章Using Tables as Queues。你的下一个挑战是要让池化速率“恰到好处”。过于激进,你的数据库会因为池化请求而变得过热。过于宽松,你的队列会在高峰时间增长,并且排干得太慢。你应该考虑使用一种完全不同的方法:使用SQL Server内置的QUEUE对象,并依赖于WAITFOR(RECEIVE)语义的魔力。这允许完全无轮询的自负载优化服务行为。实际上,还有更多:你不需要一个服务来开始。请参阅Asynchronous Procedures Execution以获得关于我所谈论的内容的解释:在SQL Server中以完全可靠的方式从Web服务调用异步启动处理。最后,如果逻辑必须在C#进程中,则可以利用External Activator,它允许处理托管在独立进程中,而不是T-SQL过程中。
QUEUE
WAITFOR(RECEIVE)
pprl5pva2#
首先你需要考虑1.轮询的频率1.你的服务是停止和启动还是支持暂停和继续。1.并发性。服务可以增加遇到问题的可能性执行情况1.使用System.Timers.Timer而不是Threading.Timer1.请确保您设置了Timer.AutoReset为false。这将阻止重入问题。1.确保包括执行时间下面是所有这些想法的基本框架,其中包括调试这个问题的方法,这是一个痛苦
public partial class Service : ServiceBase{ System.Timers.Timer timer; public Service() { timer = new System.Timers.Timer(); //When autoreset is True there are reentrancy problme timer.AutoReset = false; timer.Elapsed += new System.Timers.ElapsedEventHandler(DoStuff); } private void DoStuff(object sender, System.Timers.ElapsedEventArgs e) { Collection stuff = GetData(); LastChecked = DateTime.Now; foreach (Object item in stuff) { try { item.Dosomthing() } catch (System.Exception ex) { this.EventLog.Source = "SomeService"; this.EventLog.WriteEntry(ex.ToString()); this.Stop(); } TimeSpan ts = DateTime.Now.Subtract(LastChecked); TimeSpan MaxWaitTime = TimeSpan.FromMinutes(5); if (MaxWaitTime.Subtract(ts).CompareTo(TimeSpan.Zero) > -1) timer.Interval = MaxWaitTime.Subtract(ts).TotalMilliseconds; else timer.Interval = 1; timer.Start(); } protected override void OnPause() { base.OnPause(); this.timer.Stop(); } protected override void OnContinue() { base.OnContinue(); this.timer.Interval = 1; this.timer.Start(); } protected override void OnStop() { base.OnStop(); this.timer.Stop(); } protected override void OnStart(string[] args) { foreach (string arg in args) { if (arg == "DEBUG_SERVICE") DebugMode(); } #if DEBUG DebugMode(); #endif timer.Interval = 1; timer.Start(); } private static void DebugMode() { Debugger.Break(); } }
EDITStart()中的固定循环EDIT原来毫秒数与总毫秒数不同
wmtdaxz33#
你可能想看看Quartz.Net来管理作业的调度,不确定它是否适合你的特定情况,但值得一看。
6ojccjat4#
根据你的编辑,我能想到一些事情:回复:作业失败:
回复:争论:
回复:保持服务运行
我真的只是在黑暗中摸索,我强烈建议对服务进行原型化,然后带着关于它的工作方式的任何具体问题返回。
4条答案
按热度按时间ego6inou1#
假设您正在处理数据库队列,由于数据库的事务性,您已经完成了相当一部分工作。典型的队列驱动应用程序具有一个循环,该循环执行以下操作:
如果处理中途崩溃,事务将回滚,并在下一次服务启动时处理该项。
但是在数据库中编写队列实际上比你想象的要复杂很多。如果你使用一种幼稚的方法,你会发现你的入队和出队互相阻塞,ashx页面变得没有响应。接下来你会发现出队和出队死锁,你的循环经常遇到错误1205。我强烈建议你阅读这篇文章Using Tables as Queues。
你的下一个挑战是要让池化速率“恰到好处”。过于激进,你的数据库会因为池化请求而变得过热。过于宽松,你的队列会在高峰时间增长,并且排干得太慢。你应该考虑使用一种完全不同的方法:使用SQL Server内置的
QUEUE
对象,并依赖于WAITFOR(RECEIVE)
语义的魔力。这允许完全无轮询的自负载优化服务行为。实际上,还有更多:你不需要一个服务来开始。请参阅Asynchronous Procedures Execution以获得关于我所谈论的内容的解释:在SQL Server中以完全可靠的方式从Web服务调用异步启动处理。最后,如果逻辑必须在C#进程中,则可以利用External Activator,它允许处理托管在独立进程中,而不是T-SQL过程中。pprl5pva2#
首先你需要考虑
1.轮询的频率
1.你的服务是停止和启动还是支持暂停和继续。
1.并发性。服务可以增加遇到问题的可能性
执行情况
1.使用System.Timers.Timer而不是Threading.Timer
1.请确保您设置了Timer.AutoReset为false。这将阻止重入问题。
1.确保包括执行时间
下面是所有这些想法的基本框架,其中包括调试这个问题的方法,这是一个痛苦
EDITStart()中的固定循环
EDIT原来毫秒数与总毫秒数不同
wmtdaxz33#
你可能想看看Quartz.Net来管理作业的调度,不确定它是否适合你的特定情况,但值得一看。
6ojccjat4#
根据你的编辑,我能想到一些事情:
回复:作业失败:
回复:争论:
回复:保持服务运行
我真的只是在黑暗中摸索,我强烈建议对服务进行原型化,然后带着关于它的工作方式的任何具体问题返回。