簡體   English   中英

在Windows服務中運行長時間運行的任務

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM