![](/img/trans.png)
[英]Windows Service Application to perform long-running task only once and stop itself after completion
[英]Running a long-running Task within a Windows Service
我編寫了一個Windows服務項目,它承載了一個長期運行的消息泵任務,該任務是在服務期間運行的。 服務啟動時,它會啟動任務。 當服務停止時,它會停止任務:
void OnStart()
{
MessagePump.Start();
}
void OnStop()
{
MessagePump.Stop();
}
MessagePump.Start執行Task.Factory.StartNew,MessagePump.Stop指示任務停止並執行Wait()。
到目前為止一切都那么好,但我想知道如何最好地處理故障。 如果任務有一個未處理的異常,我希望服務停止,但由於沒有任何東西通常在等待任務,我想它只是無所事事。 我怎樣才能優雅地處理這種情況?
更新:
共識似乎是使用'await'或ContinueWith。 以下是我目前編寫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()
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.