在Windows服务中运行长时间运行的任务
本文关键字:运行 长时间 任务 Windows 服务 | 更新日期: 2023-09-27 18:23:45
我编写了一个Windows服务项目,该项目承载一个长期运行的消息泵任务,该任务旨在在服务期间运行。当服务启动时,它将启动任务。当服务停止时,它停止任务:
void OnStart()
{
MessagePump.Start();
}
void OnStop()
{
MessagePump.Stop();
}
其中MessagePump.Start执行Task.Factory.StartNew,MessagePump.Stop发出停止任务的信号并执行Wait()。
到目前为止还不错,但我想知道如何最好地处理错误。如果任务有一个未处理的异常,我希望服务停止,但由于通常没有什么东西在等待任务,我想它会无所事事。我该如何优雅地处理这种情况?
更新:
共识似乎是使用"等待"或"继续"。以下是我目前如何编码我的Start方法来使用这个:
public async static void Start()
{
this.state = MessagePumpState.Running;
this.task = Task.Factory.StartNew(() => this.ProcessLoop(), TaskCreationOptions.LongRunning);
try
{
await this.task;
}
catch
{
this.state = MessagePumpState.Faulted;
throw;
}
}
让MessagePump.Start()方法返回任务。然后
MessagePump.Start().ContinueWith(t =>
{
// handle exception
},
TaskContinuationOptions.OnlyOnFaulted);
更新:我会做下一个:
private MessagePump _messagePump;
async void OnStart()
{
this._messagePump = new MessagePump();
try
{
// make Start method return the task to be able to handle bubbling exception here
await _messagePump.Start();
}
catch (Exception ex)
{
// log exception
// abort service
}
}
void OnStop()
{
_messagePump.Stop();
}
public enum MessagePumpState
{
Running,
Faulted
}
public class MessagePump
{
private CancellationTokenSource _cancallationTokenSrc;
private MessagePumpState _state;
public async Task Start()
{
if (_cancallationTokenSrc != null)
{
throw new InvalidOperationException("Task is already running!");
}
this._state = MessagePumpState.Running;
_cancallationTokenSrc = new CancellationTokenSource();
var task = Task.Factory.StartNew(() => this.ProcessLoop(_cancallationTokenSrc.Token), _cancallationTokenSrc.Token);
try
{
await task;
}
catch
{
this._state = MessagePumpState.Faulted;
throw;
}
}
public void Stop()
{
if (_cancallationTokenSrc != null)
{
_cancallationTokenSrc.Cancel();
_cancallationTokenSrc = null;
}
}
public void ProcessLoop(CancellationToken token)
{
// check if task has been canceled
while (!token.IsCancellationRequested)
{
Console.WriteLine(DateTime.Now);
Thread.Sleep(1000);
}
}
}
您可以尝试以下操作:
void OnStart()
{
MessagePump.StartAsync();
MessagePump.ErrorEvent += OnError();
}
然后您的StartAsync将看起来像:
public async Task StartAsync()
{
// your process
// if error, send event to messagePump
}
如果您决定使用Tasks,那么最好使用Task.Run,而不是Task.Factory.StartNew()