【问题标题】:How to run a task when a windows service starts?windows服务启动时如何运行任务?
【发布时间】:2013-04-05 02:43:44
【问题描述】:

我有一个 Windows 服务,并且我已经编写了在 OnStart() 事件中运行任务的代码:

 protected override void OnStart(string[] args)
        {
            this.DoTask();
        }

private void DoTask()
        {
            Task task1 = Task.Factory.StartNew(() => this.OriginalFileProcessor.StartPolling());

            try
            {
                Task.Wait(task1);
            }
            catch (Exception ex)
            {
                this.Log.Error("Failed running the task", ex);
            }           
        }

DoTask 是一个永无止境的循环。只有在服务停止时才会停止。

但是当我尝试启动服务时,它会等待很长时间然后给我以下错误:

Windows could not start the ... service on Local Computer.
Error 1053: The service did not respond to the start or control request in a timely fashion.

如何解决?

【问题讨论】:

    标签: c# .net windows-services installutil onstart


    【解决方案1】:

    你为什么要等你的任务完成?

    我认为Task.Wait 正在阻塞您当前的线程,然后您在启动服务时会超时。

    编辑:您需要删除此块:

    try
    {
        Task.Wait(task1);
    }
    catch (Exception ex)
    {
        this.Log.Error("Failed running the task", ex);
    }  
    

    Task.Wait 确实阻塞了您当前的线程。根据MSDN

    Task.Wait 方法

    等待任务完成执行。

    EDIT 2改为这样做

    Task task1 = Task.Factory.StartNew(() => this.OriginalFileProcessor.StartPolling()).ContinueWith( t =>
    {
         var aggException = t.Exception.Flatten();
         foreach(var ex in aggException.InnerExceptions)
             this.Log.Error("Failed running the task", ex);
    }, 
    TaskContinuationOptions.OnlyOnFaulted);
    

    【讨论】:

    • 等待不是等待。我的意思是它只会捕获该任务的任何异常。
    • 等待的“就这样等待”。您的代码坐在那里,什么也不做,等待该任务完成。它在调用OnStart 的同一线程上等待。
    • 检查我的编辑,并继续执行任务。您无法在服务启动期间检查异常,因为这个过程似乎需要时间,并且可能会给您超时。
    【解决方案2】:

    我猜是这样,因为您正在等待OriginalFileProcessor.StartPolling() 结束,但这永远不会发生。您应该将您的任务实例移动到一个单独的成员中,而不是等待它完成:

    private Task m_task = null;
    
    private void DoTask()
    {
        try
        {
            m_task = Task.Factory.StartNew(() => this.StartPolling());
        }
        catch
        {
            this.Log.Error("Unable to start task", ex);
            throw;  // Rethrow, so that the OS knows, there was something wrong.
        }           
    }
    
    private void StartPolling()
    {
        try
        {
            this.OriginalFileProcessor.StartPolling();
        }
        catch (Exception ex)
        {
            this.Log.Error("Failed running the task", ex);
        }
    }
    

    【讨论】:

    • 你的捕获永远不会捕获。只有当你等待它时它才能捕捉到。
    • @TheLight:它应该只捕获来自Task.Factory.StartNew 的异常,而不是来自StartPolling 的异常。您正在启动服务以异步运行,而不是等待它完成。更新了答案。
    • Task.Factory.StartNew 不返回异常。您可以在等待任务时捕获异常。还是有其他方法?
    【解决方案3】:

    在循环中,您需要检查服务状态是否为“停止”并退出循环。在操作系统决定杀死你之前,你有 5 秒钟的时间来执行此操作。

    【讨论】: