2011-10-03 26 views
10

csharp-example并正式开始注意到与SO有关问题(Restart a windows services from C#Cannot restart a Service)以及其他各种问题,重新启动只是一个服务,我想知道,最好的方法是什么重新启动服务与相关服务 (例如Message Queuing,其上Message Queuing Triggers取决于,或者IIS,其中FTP PublishingWorld Wide Web Publishing取决于)。 mmc管理单元自动执行此操作,但代码似乎没有提供相同的功能(至少不那么容易)。重新启动具有相关服务的服务?

MSDN documentation for Stop说:“如果任何服务依赖于该服务为他们的运营,他们将停止此服务被终止之前的DependentServices属性包含一套依赖于这个服务的,”和DependentServices返回一系列的服务。假设StartService()和​​遵循的例子,并概述了公约,如上述(除非他们接受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 B1Service B2Service C1取决于Service B1,似乎“重新启动”通过这种方法Service A将停止Service C1,但不会重新启动它...

为了使这个例子画面更清晰,我会按照在服务MMC管理模式管理单元:

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

是否有更好的方法去这个,还是只是递归地进入并停止每个依赖服务,然后在重启主服务后重新启动它们?

此外,将从属于目前停止服务将列在依赖服务?如果是这样,反正他们不会重新启动它们吗?如果是这样,我们是否应该控制它?这似乎变得更混乱和更混乱...

*注意:我意识到timeout没有被正确应用在这里(总体超时可能比预期长很多倍),但现在不是这个问题我很担心 - 如果你想修复它,但没关系,只是不要说'超时'坏了......'

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

  • 停止服务(例如Service A)的其他服务(E 。G。 Service B1)取决于将停止其他服务(包括“嵌套”的依赖关系如Service C1
  • DependentServices确实包括在所有状态相关的服务(运行,停止等),并且它也包括嵌套的依赖关系,即Service_A.DependentServices将包含{Service B1, Service C1, Service B2}(以该顺序,因为C1取决于B1)。
  • 启动一项取决于他人的服务(例如Service B1取决于Service A)也将启动必要的服务。

的代码因此上述可以被简化(至少部分地)到刚停止主服务(这将停止所有相关服务),然后重新启动最依赖的服务(例如Service C1Service B2)(或只是重新启动“所有”依赖服务 - 它会跳过已经启动的服务),但这只是暂时延迟主服务的启动,直到其中一个依赖项抱怨为止,所以这并没有什么帮助。

看起来现在好像刚刚重新启动所有的依赖是最简单的方式,但忽略了(现在)管理那些已经停止服务,并且这样的......

回答

4

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

再次,StartService(),​​和RestartService()方法遵循在实施例中列出,并已等在问题本身所引用的约定(即它们包裹启动/停止行为,避免“已启动/停止”型例外)与补充说明如果传入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; 
     } 
    } 
} 
+1

评论“他们以前的状态是压力在集合中出现“是无效的。当我执行此代码时,状态似乎已更新。所以我不得不修改它来记录主服务重启之前的初始状态。也许.NET内部实现自发布后发生了变化? – Stif

1

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

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

当您重新启动基本服务时,您可以运行这个列表并开始一切。如果您没有重新排列列表,服务应该以正确的顺序开始,一切都会好的。

+0

是啊,这就是结论,我看中以及...这不是非常困难,它只是比automagic mmc更复杂 - 哦,以及... :) – johnny

+0

事实证明,它不需要递归 - 注意(从我的更新)获取依赖关系在一个基地列出依赖的顺序依赖的服务,所以你只需要过滤该列表的实际运行之前,你重新启动基地... – johnny

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

问题的兴趣:

对于代码clearity我没加:

  • 超时
  • 错误检查

请注意,该应用程序可以在一个陌生的国家,结束时,一些服务将重新启动,有些则不是...

+0

在您的if语句中,您还需要在添加之前检查服务是否正在运行。如果 { controllers.Add(控制器)(dependencyAdded && controllers.Contains(控制器)&&(controller.status = ServiceControllerStatus.Stopped && controller.status = ServiceControllerStatus.StopPending)!!); } – user398039