[英]Running a long-running Task within a Windows Service
I have written a Windows Service project which hosts a long-running message pump task which is meant to run for the duration of the service. 我编写了一个Windows服务项目,它承载了一个长期运行的消息泵任务,该任务是在服务期间运行的。 When the service starts, it starts the task.
服务启动时,它会启动任务。 When the service stops, it stops the task:
当服务停止时,它会停止任务:
void OnStart()
{
MessagePump.Start();
}
void OnStop()
{
MessagePump.Stop();
}
Where MessagePump.Start does a Task.Factory.StartNew, and MessagePump.Stop signals the task to stop and does a Wait(). MessagePump.Start执行Task.Factory.StartNew,MessagePump.Stop指示任务停止并执行Wait()。
So far so good, but I'm wondering how best to handle faults. 到目前为止一切都那么好,但我想知道如何最好地处理故障。 If the task has an unhandled exception, I'd want the service to stop but since nothing is typically Wait-ing on the task, I imagine it'll just sit doing nothing.
如果任务有一个未处理的异常,我希望服务停止,但由于没有任何东西通常在等待任务,我想它只是无所事事。 How can I elegantly handle this situation?
我怎样才能优雅地处理这种情况?
UPDATE: 更新:
The consensus seems to be using 'await' or ContinueWith. 共识似乎是使用'await'或ContinueWith。 Here is how I'm currently coding my Start method to use this:
以下是我目前编写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;
}
}
Make you MessagePump.Start() method return the task. 让你MessagePump.Start()方法返回任务。 Then
然后
MessagePump.Start().ContinueWith(t =>
{
// handle exception
},
TaskContinuationOptions.OnlyOnFaulted);
UPDATE: I would do the next: 更新:我会做下一个:
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);
}
}
}
You can try something like this : 你可以尝试这样的事情:
void OnStart()
{
MessagePump.StartAsync();
MessagePump.ErrorEvent += OnError();
}
Then your StartAsync will look something like: 然后你的StartAsync看起来像:
public async Task StartAsync()
{
// your process
// if error, send event to messagePump
}
And if you decide to use Tasks, then it is better to use Task.Run and not Task.Factory.StartNew() 如果你决定使用Tasks,那么最好使用Task.Run而不是Task.Factory.StartNew()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.