我编写了一个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;
}
}
答案 0 :(得分:2)
让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);
}
}
}
答案 1 :(得分:1)
您可以尝试这样的事情:
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()