C# 当Win service收到暂停或停止时,继续执行任务的最佳方式是什么?

C# 当Win service收到暂停或停止时,继续执行任务的最佳方式是什么?,c#,.net,windows,service,windows-services,C#,.net,Windows,Service,Windows Services,因此,我成功地编写了该服务,目前它运行良好。假设我要确保在处理数据库记录时,以及由于某种原因,如果服务暂停或关闭,任务应该完成,而不是让数据不一致 我试过下面的代码,但我觉得它可能不正确,如果是,它可能不是最好的。如何针对上述场景改进此代码 protected override void OnStart(string[] args) { // Update the service state to Start Pending. ServiceStatus serviceStatu

因此,我成功地编写了该服务,目前它运行良好。假设我要确保在处理数据库记录时,以及由于某种原因,如果服务暂停或关闭,任务应该完成,而不是让数据不一致

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

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事务模式,因为我无法控制第二台远程服务器

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

这里的“定期”需要一些猜测,但它需要足够频繁,以确保服务控制经理不会将您的服务视为未关闭。过去我每隔几秒钟就做一次,没有问题


如果您有任何需要花费很长时间(超过几十秒)才能完成的事情,您确实需要重新构造,以便在服务重新启动时恢复(请记住,关闭可能是因为系统即将断电或需要尽快停止)。

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


你试图修复SCM交互完全是找错了方向。您的重点应该放在数据库工作上,确保您的事务边界正确。

这很有用,但不会解决问题,也就是说,此服务正在处理数据并向第二台服务器发送请求。第二台服务器将处理数据,如果我回滚并重做数据,这意味着我将再次处理相同的请求。在分布式事务中注册这两台服务器。或者使用可靠的消息传递协议。整个问题领域都得到了很好的研究和理解。尝试使服务“防故障”不是一个选项。我无法控制由ISP拥有的远程服务器。我使用windows服务通过他们提供的API进行调用,windows服务负责从DB获取记录并将其传递到远程服务器。我遇到了这个问题,但真正能够理解线程部分。如果SendScheduledSMS占用的时间超过了我在等待提示中设置的时间,会发生什么?如果代码仍在执行或花费的时间超出预期,我如何更新等待提示?@Hitin我没有说这很容易:这就是为什么不容易。您需要在一个线程上执行发送,同时在另一个线程上更新SCM(使用线程池:不要执行自己的线程管理),但是您还需要确定如果发送未完成该怎么办。
serviceStatus.dwCurrentState = ServiceState.SERVICE_STOP_PENDING;
serviceStatus.dwWaitHint = 100000;
SetServiceStatus(this.ServiceHandle, ref serviceStatus);