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

从csharp示例开始并正式注意相关的SO问题( 从C#重新启动Windows服务并且无法重新启动服务 )以及与重新启动一项服务相关的各种其他问题,我想知道重启服务的最佳方法是什么依赖服务 (例如, Message Queuing Triggers依赖的Message Queuing Triggers ,或者是FTP PublishingWorld Wide Web Publishing依赖的IIS )。 mmc管理单元自动执行此操作,但代码似乎不提供相同的function(至少不那么容易)。

Stop的MSDN文档说“如果任何服务依赖于此服务进行操作,它们将在此服务停止之前停止.DependentServices属性包含依赖于此服务的服务集”,并且DependentServices返回一组服务。 假设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 B1 依赖于 Service B1Service B2Service C1 依赖于 Service B1 ,那么它似乎是“重新启动” Service A通过这种方法将停止Service C1但不会重新启动它…

为了使这个示例图片更清晰,我将遵循服务mmc管理单元中的模型:

 The following system components depend on [Service A]: - Service B1 - Service C1 - Service B2 

有没有更好的方法来解决这个问题,还是只需要递归地进入并停止每个依赖服务,然后在重新启动主服务后重新启动它们?

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

*注意:我意识到这里没有完全正确地应用超时(整体超时可能比预期长很多倍),但是现在这不是我关心的问题 – 如果你想修复它,很好,但不要只是说’超时被打破……’

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

  • 停止其他服务(例如Service B1 )所依赖的服务(例如Service A )将停止其他服务(包括“嵌套”依赖性,例如Service C1
  • DependentServices 确实包括所有状态(运行,停止等)的依赖服务,它还包括嵌套依赖项,即Service_A.DependentServices将包含{Service B1, Service C1, Service B2} (按顺序,因为C1依赖于B1 )。
  • 启动依赖于其他Service B1 (例如, Service B1 依赖于 Service A )也将启动必需的服务。

因此,上面的代码可以简化(至少部分)只是停止主服务(将停止所有相关服务),然后重新启动最依赖的服务(例如Service C1Service B2 )(或者只是重新启动“全部”)依赖服务 – 它将跳过已经开始的服务),但这只是暂时推迟主服务的启动,直到其中一个依赖关系抱怨它,所以这并没有真正帮助。

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

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

同样, StartService()StopService()RestartService()方法遵循示例中概述的约定,并且已在问题本身中引用(即它们包装Start / Stop行为以避免“已启动/已停止”类型的exception)如果传入Service (如下所示),则在检查其Status之前,在该服务上调用Refresh()

 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; } } } 

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

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

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

请注意ServiceController.Stop()停止’依赖’服务, ServiceController.Start()启动’依赖’服务 – 因此在停止服务后,您只需要启动依赖树叶的服务。

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

  private static void FillDependencyTreeLeaves(ServiceController controller, List 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 dependencies = new List(); 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(); } 

兴趣点:

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

  • 超时
  • 错误检查

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