使用从属服务重新启动服务?

时间:2011-10-03 18:58:32

标签: c# .net windows-services

csharp-example开始并及时注意到相关的SO问题(Restart a windows services from C#Cannot restart a Service)以及与重新启动一项服务相关的各种其他问题,I'我想知道重新启动服务使用相关服务 的最佳方法(例如Message Queuing取决于Message Queuing TriggersIIS } {,FTP PublishingWorld Wide Web Publishing依赖)。 mmc管理单元自动执行此操作,但代码似乎没有提供相同的功能(至少不那么容易)。

MSDN documentation for Stop说“如果任何服务依赖于此服务进行操作,它们将在此服务停止之前停止.DependentServices属性包含依赖于此服务的一组服务”和{{3返回一组服务。假设StartService()StopService()遵循示例中列出的约定以及上面引用的约定(除了它们直接接受ServiceControllersTimeSpans),我开始使用:

public static void RestartServiceWithDependents(ServiceController service, TimeSpan timeout)
{
    ServiceController[] dependentServices = service.DependentServices;

    RestartService(service, timeout); // will stop dependent services, see note below* about timeout...

    foreach (ServiceController dependentService in dependentServices)
    {
        StartService(dependentService, timeout);
    }
}

但是,如果服务依赖项是嵌套的(递归的)或循环的(如果可能的话......) - 如果Service A 依赖 Service B1和{ {1}}和Service B2 取决于 Service C1,此方法似乎“重新启动”Service B1会停止Service A,但不会重启它...

为了使这个示例图片更清晰,我将按照服务mmc管理单元中的模型进行操作:

Service C1

是否有更好的方法可以解决这个问题,还是只需递归步入并停止每个相关服务,然后在重新启动主服务后重新启动它们?

此外,依赖当前停止的服务是否列在DependentServices下?如果是这样,这不会重新启动它们吗?如果是这样,我们也应该控制它吗?这似乎变得更加混乱和混乱......

*注意:我意识到The following system components depend on [Service A]: - Service B1 - Service C1 - Service B2 没有在这里完全正确应用(整体超时可能比预期长很多倍),但是现在这不是我关心的问题 - 如果你想要解决它,很好,但不要只是说'超时被打破......'

更新:经过一些初步测试后,我发现(/确认)了以下行为:

  • 停止其他服务(例如timeout)所依赖的服务(例如Service A)将停止其他服务(包括“嵌套”依赖项,例如Service B1
  • DependentServices 在所有状态(运行,停止等)中包含依赖服务,并且还包含嵌套依赖项,即Service C1将包含Service_A.DependentServices }(按此顺序,{Service B1, Service C1, Service B2}取决于C1)。
  • 启动依赖他人的服务(例如B1 取决于 Service B1)也将启动必要的服务。

因此,可以简化上述代码(至少部分)以停止主服务(将停止所有相关服务),然后重新启动最依赖的服务(例如Service A和{{1} }(或者只是重新启动“所有”依赖服务 - 它将跳过已经启动的服务),但这实际上只是暂时推迟主服务的启动,直到其中一个依赖项抱怨它,所以这并没有真正的帮助

现在寻找只是重新启动所有依赖项是最简单的方法,但是忽略(现在)管理已停止的服务等等......

3 个答案:

答案 0 :(得分:4)

好吧,终于实现了这一点。我已将其作为一个单独的答案发布,因为我已在第一个答案之前发布的问题的原始更新中得出了这个结论。

同样,StartService()StopService()RestartService()方法遵循示例中概述的约定,并且已经在问题本身中引用了这些约定(即它们包含启动/停止行为以避免“已经开始/停止了“-type例外”,并附有一个附录,如果传入Service(如下所示),则在检查Refresh()之前,会在该服务上调用Status

public static void RestartServiceWithDependents(ServiceController service, TimeSpan timeout)
{
    int tickCount1 = Environment.TickCount; // record when the task started

    // Get a list of all services that depend on this one (including nested
    //  dependencies)
    ServiceController[] dependentServices = service.DependentServices;

    // Restart the base service - will stop dependent services first
    RestartService(service, timeout);

    // Restore dependent services to their previous state - works because no
    //  Refresh() has taken place on this collection, so while the dependent
    //  services themselves may have been stopped in the meantime, their
    //  previous state is preserved in the collection.
    foreach (ServiceController dependentService in dependentServices)
    {
        // record when the previous task "ended"
        int tickCount2 = Environment.TickCount;
        // update remaining timeout
        timeout.Subtract(TimeSpan.FromMilliseconds(tickCount2 - tickCount1));
        // update task start time
        tickCount1 = tickCount2;
        switch (dependentService.Status)
        {
            case ServiceControllerStatus.Stopped:
            case ServiceControllerStatus.StopPending:
                // This Stop/StopPending section isn't really necessary in this
                //  case as it doesn't *do* anything, but it's included for
                //  completeness & to make the code easier to understand...
                break;
            case ServiceControllerStatus.Running:
            case ServiceControllerStatus.StartPending:
                StartService(dependentService, timeout);
                break;
            case ServiceControllerStatus.Paused:
            case ServiceControllerStatus.PausePending:
                StartService(dependentService, timeout);
                // I don't "wait" here for pause, but you can if you want to...
                dependentService.Pause();
                break;
        }
    }
}

答案 1 :(得分:1)

听起来你想重新启动一个“基础”服务并让所有依赖它的东西也重新启动。如果是这样,您不能只重新启动所有相关服务,因为它们可能没有预先运行。我知道没有这方面的API。

我这样做的方法就是编写一个递归函数来扫描所有相关服务(及其依赖项),并按顺序将所有正在运行的服务添加到列表中。< / p>

当您重新启动基本服务时,您可以只运行此列表并启动所有内容。如果您没有对列表进行重新排序,那么服务应该以正确的顺序开始,一切都会顺利进行。

答案 2 :(得分:1)

请注意ServiceController.Stop()停止'依赖'服务和ServiceController.Start()启动'依赖于'服务 - 因此在停止服务后,您只需要启动依赖树离开的服务。

假设不允许循环依赖,以下代码获取需要启动的服务:

    private static void FillDependencyTreeLeaves(ServiceController controller, List<ServiceController> controllers)
    {
        bool dependencyAdded = false;
        foreach (ServiceController dependency in controller.DependentServices)
        {
            ServiceControllerStatus status = dependency.Status;
            // add only those that are actually running
            if (status != ServiceControllerStatus.Stopped && status != ServiceControllerStatus.StopPending)
            {
                dependencyAdded = true;
                FillDependencyTreeLeaves(dependency, controllers);
            }
        }
        // if no dependency has been added, the service is dependency tree's leaf
        if (!dependencyAdded && !controllers.Contains(controller))
        {
            controllers.Add(controller);
        }
    }

使用简单的方法(例如扩展方法):

    public static void Restart(this ServiceController controller)
    {
        List<ServiceController> dependencies = new List<ServiceController>();
        FillDependencyTreeLeaves(controller, dependencies);
        controller.Stop();
        controller.WaitForStatus(ServiceControllerStatus.Stopped);
        foreach (ServiceController dependency in dependencies)
        {
            dependency.Start();
            dependency.WaitForStatus(ServiceControllerStatus.Running);
        }
    }

您只需重新启动服务即可:

    using (ServiceController controller = new ServiceController("winmgmt"))
    {
        controller.Restart();
    }

兴趣点:

为了代码清晰,我没有添加:

  • 超时
  • 错误检查

请注意,当某些服务重新启动而某些服务没有重新启动时,应用程序可能会处于一种奇怪的状态......