背景:
- 运行Window Server 2008 R2
- 服务器已经修补了所有最近的更新
- 服务器运行在.NET 3.5中构建的5个服务,所有这些服务都使用计时器重复检查数据库(大多每10秒)。
- 这些服务不是CPU / RAM密集型的
- 服务器没有任何性能和资源问题或瓶颈。
在大多数情况下,一切都按预期工作,但有时(或所有)服务只是停止工作。我正在将所有应用程序异常记录到文件中,但在失败时没有。事件记录器中也没有错误,服务管理器将服务视为正在运行。我必须停止服务并再次启动它们以恢复功能。
此行为无法预测,有时需要一周或一个月才能停止工作。此外,有时服务会同时“死”或同时“死”。
只有我想到的是Timer对象。我一直在使用System.Timers.Timer并发现几个论坛帖子说明它不可靠,因为垃圾收集器可能释放实例。我尝试使用GC.KeepAlive()保留它无济于事。我已经遵循了一些关于将System.Timers.Timer移动到System.Threading.Timer的建议,但这也没有任何区别。
此刻,我迫不及待地想知道这种行为的来源。有没有已知的类似问题?如果没有引发异常并且事件日志也是静默的,我该如何调试它?
感谢您提供任何可能导致任何解决方案的建议。
更新:包括当前状态的裸机代码:
private System.Threading.Timer timerPublish = null;
private bool timerDelegateMethodRunning = false;
protected override void OnStart(string[] args)
{
SetupTimer();
}
protected override void OnStop()
{
if (timerPublish != null)
{
timerPublish.Dispose();
}
}
public void SetupTimer()
{
if (timerPublish != null)
{
timerPublish.Dispose();
}
TimerCallback callbackMethod = new TimerCallback(this.timerPublish_Elapsed);
timerPublish = new System.Threading.Timer(callbackMethod, null, 5000, 5000);
}
void timerPublish_Elapsed(Object stateInfo)
{
if (timerDelegateMethodRunning)
{
return;
}
timerDelegateMethodRunning = true;
try
{
// Processing code here
}
finally
{
timerDelegateMethodRunning = false;
}
}
更新2:谢谢你们的见解和建议。一旦问题再次发生,我将尝试调试生产服务器上的服务。我会在有任何新内容(可能在几周内)后立即报告。
答案 0 :(得分:3)
为什么让事情复杂化? :)准备好后,只需使用Timer.Change()
方法再次触发计时器。
另请注意,WorkerMethod
中的任何未捕获的例外情况都会 f * ckup您的服务。
public class YourService
{
private System.Threading.Timer _timer;
protected override void OnStart(string[] args)
{
//run once in 5 seconds.
_timer = new System.Threading.Timer(WorkerMethod, null, 5000, Timeout.Infinite);
}
protected override void OnStop()
{
if (_timer != null)
{
_timer.Dispose();
_timer = null;
}
}
void WorkerMethod(object state)
{
// Processing code here
_worker.Change(5000, Timeout.Infinite); //Run again in 5 seconds
}
}
我看到你在哪里使用System.Timers.Timer
。最大的问题是 忽略异常 。也就是说,如果您的代码抛出异常并且您没有抓住它: 您将永远不会意识到该异常 。这可能是你的问题。
答案 1 :(得分:1)
在你知道挂起的原因之前,不要过早得出结论。可能有各种令人难以置信的因素,但转储分析或实时调试可以说实话,
http://blogs.msdn.com/b/tess/archive/2006/10/16/net-hang-debugging-walkthrough.aspx
如果您愿意,您甚至可以通过http://support.microsoft.com
打开支持案例答案 2 :(得分:0)
无论如何,我可能会建议你的服务略有改变;在我们有readonly
Timer
的地方,在初始分配后,只需要切换来运行,而不是在某一刻发生处理的方式,并保留我们自己的硬引用TimerCallback
。至少,我们将对象的处理留给服务本身(至少是我们困扰的长期对象)。
虽然这种模式可能不是你手套的白兔,但我可以保证以这种方式构建的许多服务的可靠性。因此,如果问题在实施后仍然存在,那么我会非常自信地说// Processing code here
后面的内容本身就存在问题。
private readonly System.Threading.Timer Timer = null;
private readonly System.Threading.TimerCallback Callback = null;
private readonly int Interval = 5000;
public MyService()
{
Callback = new TimerCallback(this.timerPublish_Elapsed);
Timer = new System.Threading.Timer(Callback, null, Timeout.Infinite, Timeout.Infinite);
}
private void Start()
{
Timer.Change(Timespan.Zero, Interval);
}
private void Stop()
{
Timer.Change(Timeout.Inifinite, Timeout.Inifnite);
}
protected override void OnStart(string[] args)
{
Start();
}
protected override void OnStop()
{
Stop();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if(disposing)
{
if(Timer != null)
Timer.Dispose();
}
}