Перезапустить службу с зависимыми службами?

начиная с csharp-пример и должным образом отмечая связанные с этим вопросы (перезапустите службы windows с C# и не удается перезапустить службу) и различные другие вопросы, касающиеся перезапуск только одну услугу, мне интересно, какой лучший метод для перезагрузка с зависимыми услуги (например,Message Queuing, на котором Message Queuing Triggers зависит, или IIS, на котором FTP Publishing и World Wide Web Publishing зависеть.) Оснастка mmc делает это автоматически, но код, похоже, не обеспечивает ту же функциональность (по крайней мере, не так легко).

документация MSDN для остановки говорит: "Если какие-либо службы зависят от этой службы для их работы, они будут остановлены до остановки этой службы. Свойство DependentServices содержит набор служб, зависящих от этого свойства" и DependentServices возвращает массив услуги. Предполагая StartService() и StopService() следуйте соглашениям, изложенным в примерах и таких ссылках выше (за исключением того, что они принимают ServiceControllers и TimeSpans напрямую), я начал с:

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 и зависит от by Service B1 и Service B2 и Service C1 зависит от Service B1, кажется, 'перезагрузки' Service A этим методом остановки Service C1 но не перезагрузка он...

чтобы сделать этот пример более ясным, я буду следовать модели в оснастке mmc служб:

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

есть ли лучший способ сделать это, или ему просто нужно рекурсивно войти и остановить каждую зависимую службу, а затем перезапустить их все после перезапуска основной службы?

дополнительно зависимая но в настоящее время остановлен службы перечислены в разделе DependentServices? Если это так, то не это перезапустить их в любом случае? Если да, то должны ли мы контролировать и это? Это становится все более и более запутанным...

*примечание: Я понимаю timeout не применяется полностью правильно здесь (общий тайм-аут может быть во много раз дольше, чем ожидалось), но на данный момент это не проблема, о которой я беспокоюсь - если вы хотите исправить это, хорошо, но не просто сказать " тайм-аут сломан...'

обновление: после некоторого предварительного тестирования я обнаружил (/подтверждено) следующее поведение:

  • остановка службы (например,Service A), что другие услуги (например Service B1) depend on остановит другие службы (включая" вложенные " зависимости, такие как Service C1)
  • DependentServices тут включить зависимые службы во всех состояниях (запущенные, остановленные и т. д.), а также включает вложенные зависимости, т. е. Service_A.DependentServices содержит {Service B1, Service C1, Service B2} (именно в таком порядке, как C1 зависит от B1).
  • запуск службы, которая зависит от других (например,Service B1 зависит от Service A) и начнет необходимые услуги.

поэтому приведенный выше код можно упростить (по крайней мере частично), чтобы просто остановить основную службу (которая остановит все зависимые службы), а затем перезапустить наиболее зависимые службы (например,Service C1 и Service B2) (или просто перезапуск" всех " зависимых служб - он пропустит те, которые уже запущены), но это действительно просто откладывает запуск основной службы на мгновение, пока одна из зависимостей не пожалуется на это, так что это действительно не помогает.

выглядит сейчас как просто перезапуск всех зависимостей является самым простым способом, но это игнорирует (на данный момент) управление службами, которые уже остановлены и такие...

3 ответов


хорошо, наконец-то реализовал это. Я разместил его как отдельный ответ, поскольку я уже пришел к этому выводу в исходном обновлении моего вопроса, который был опубликован до первого ответа.

опять StartService(), StopService() и RestartService() методы следуют соглашениям, изложенным в примерах, и такие уже упоминаются в самом вопросе (т. е. они обертывают поведение запуска/остановки, чтобы избежать исключений типа "уже запущено / остановлено") с добавлением, что если 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;
        }
    }
}

похоже, вы хотите перезапустить "базовую" службу и перезапустить все, что на нее полагается. Если это так, вы не можете просто перезапустить все зависимые службы, потому что они, возможно, не были запущены заранее. Для этого нет API, о котором я знаю.

то, как я бы это сделал, - это просто написать рекурсивную функцию для сканирования всех зависимых служб (и их зависимостей) и добавить все службы , которые были запущены в список в порядок.

когда вы перезапускаете базовую службу, вы можете просто запустить этот список и запустить все. Если вы еще не отсортировали список, услуги должны начинаться в правильном порядке, и все будет хорошо.


Пожалуйста, обратите внимание, что 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();
    }

достопримечательности:

для ясности кода я не добавил:

  • ожидания
  • проверка

обратите внимание, что приложение может оказаться в странном состоянии, когда некоторые службы перезапускаются, а некоторые нет...