在Windows服务中运行长时间运行的任务

时间:2014-09-19 08:55:15

标签: c# windows-services task-parallel-library

我编写了一个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;
    }
}

2 个答案:

答案 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()