当Win服务收到暂停或停止时,继续任务的最佳方法是什么?

时间:2015-07-07 09:34:43

标签: c# .net windows service windows-services

所以我设法写了这个服务,现在正常工作。我想确保在处理数据库记录时,由于某种原因,如果服务暂停或关闭,应该完成任务而不是让数据不一致。

我已尝试过下面的代码,但我觉得它可能不正确,如果是,它可能不是最好的。如何针对上述场景改进此代码?

protected override void OnStart(string[] args)
{
    // Update the service state to Start Pending.
    ServiceStatus serviceStatus = new ServiceStatus();
    serviceStatus.dwCurrentState = ServiceState.SERVICE_START_PENDING;
    serviceStatus.dwWaitHint = 100000;
    SetServiceStatus(this.ServiceHandle, ref serviceStatus);

    _eventLog.WriteEntry("RMS Service Started: " + DateTime.UtcNow.ToLongDateString());
    CheckDBEntryData();

    _timer = new System.Timers.Timer();
    _timer.Interval = 60000;
    _timer.Elapsed += new System.Timers.ElapsedEventHandler(this.SendScheduledSMS);
    _timer.Start();

    // Update the service state to Running.
    serviceStatus.dwCurrentState = ServiceState.SERVICE_RUNNING;
    SetServiceStatus(this.ServiceHandle, ref serviceStatus);
}
public void SendScheduledSMS(object sender, System.Timers.ElapsedEventArgs e)
    {
        if (!_isTaskRunning)
        {
            _timer.Enabled = false;
            _isTaskRunning = true;
            _eventLog.WriteEntry("RMS Timer Event started: " + DateTime.UtcNow.ToLongDateString());

            //TODO: Write the code to check pending RMS and process them

            _eventLog.WriteEntry("RMS Timer Event stopped: " + DateTime.UtcNow.ToLongDateString());
            _isTaskRunning = false;
            _timer.Enabled = true;
        }
    }
protected override void OnStop()
{
    CanStop = !_isTaskRunning;
    // Update the service state to Stop Pending.
    ServiceStatus serviceStatus = new ServiceStatus();
    serviceStatus.dwCurrentState = ServiceState.SERVICE_STOP_PENDING;
    serviceStatus.dwWaitHint = 100000;
    SetServiceStatus(this.ServiceHandle, ref serviceStatus);

    _eventLog.WriteEntry("RMS Service Stopped: " + DateTime.UtcNow.ToLongDateString());


    // Update the service state to Stopped.
    serviceStatus.dwCurrentState = ServiceState.SERVICE_STOPPED;
    SetServiceStatus(this.ServiceHandle, ref serviceStatus);
}

更多信息

服务正在处理数据库记录并将数据传递给第二远程服务器,该服务器负责向用户发送SMS通知。我需要确保通知只发送一次。如果我使用事务,并且最后一条记录发生回滚,则下次处理开始时,它将从头开始发送通知,从而发送重复通知。因此我不能依赖DB事务模式,因为我无法控制第二个远程服务器。

2 个答案:

答案 0 :(得分:1)

服务可以随时突然停止。它可能会崩溃,或者电源可能会中断。在上述任何情况下,结果应该是一致的。这就是在与数据库交互时使用事务的原因:当数据库处于一致状态时提交。如果发生中断(崩溃,SCM停止,断电,任何事情),DB将回滚到先前的一致状态。

你完全咆哮着试图修复SCM交互的错误树。您的重点应放在数据库工作上,确保您的事务边界正确。

答案 1 :(得分:0)

serviceStatus.dwCurrentState = ServiceState.SERVICE_STOP_PENDING;
serviceStatus.dwWaitHint = 100000;
SetServiceStatus(this.ServiceHandle, ref serviceStatus);

在完成任何现有任务时,您需要定期设置服务状态,并提供适当减少的等待提示。

"定期"这里需要一些猜测,但需要经常足以确保服务控制管理器不会将您的服务视为不关闭。在过去,我每隔几秒钟就会毫无问题地做到这一点。

如果您有任何需要花费大量时间(超过几十秒)的事情来完成,您确实需要对事物进行重组,以便在服务重启时恢复(请记住关闭可能是因为系统即将失去权力或以其他方式需要尽快停止。)