2

我有一个小的 Windows 服务,它应该在用户设置的固定时间间隔内每天将一些数据写入 Web 服务。

例如。从 8:00 到 22:00 每 20 分钟一班

但是在触发回调 10 次左右后,计时器停止,事件日志中没有任何内容,服务工作正常,这意味着没有异常使他崩溃。

代码很简单:

private Dictionary<string, Timer> m_timers = new Dictionary<string, Timer>();

protected override void OnStart(string[] args)
{
      // load settings

      foreach(var settings in userSettings)
      {
         SetUpTimer(settings);
      }
}

private void Callback(Settings settings)
{
    try
    {
       //Write some data to web service
       //Write to event log that web service write suceeded
    }
    catch(Exception ex)
    {
       //Write to event log
    }

    SetUpTimer(settings);
}

private void SetUpTimer(Settings settings)
{
    Timer timer;

    if (m_timers.ContainsKey(settings.Name))
    {
        timer = m_timers.Where(x => x.Key == settings.Name).Select(x => x.Value).FirstOrDefault();
        // Dispose timer (there is rumor that it can slide after few days), just to be sure.

        if (timer != null)
            timer.Dispose();
    }

    TimeSpan timeToFirstRun = settings.TimeFrom - DateTime.Now.TimeOfDay;

    while (timeToFirstRun.TotalHours < 0 || timeToFirstRun > settings.TimeTo)
    {
        timeToFirstRun += TimeSpan.FromMinutes(settings.EveryHowMuch);
    }

    if (timeToFirstRun > settings.TimeTo)
        timeToFirstRun = settings.TimeFrom - DateTime.Now.TimeOfDay + TimeSpan.FromDays(1.0);

    timer = new Timer(Callback, settings, timeToFirstRun, new TimeSpan(-1));

    if (!m_timers.ContainsKey(settings.Name))
    {
        m_timers.Add(settings.Name, timer);
    }

    // Write to event log that it sucessfully set up for next callback
}
4

1 回答 1

4

好吧,你这里有一个很大的缺陷:

您处置了一个计时器,但您没有将其从m_timers. 新创建的具有此名称的计时器将永远不会添加到字典中,因此会在某个时候被 GC 收集。

此外,您应该使用TryGetValue而不是ContainsKey与 LINQ 查询结合使用。

您的方法的顶部应如下所示:

Timer timer;
if(m_timers.TryGetValue(settings.Name, out timer))
{
    timer.Dispose();
    m_timers.Remove(settings.Name);
}
于 2013-02-04T10:00:25.893 回答