Перезапустить службу с зависимыми службами?
начиная с 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();
}
достопримечательности:
для ясности кода я не добавил:
- ожидания
- проверка
обратите внимание, что приложение может оказаться в странном состоянии, когда некоторые службы перезапускаются, а некоторые нет...