2011-10-03 29 views
10

Bắt đầu với một csharp-example và hợp lệ ghi nhận liên quan SO câu hỏi (Restart a windows services from C#Cannot restart a Service) và các câu hỏi khác nhau liên quan đến khởi động lại chỉ là một dịch vụ, tôi đang tự hỏi những gì các phương pháp tốt nhất là cho khởi động lại một dịch vụ với các dịch vụ phụ thuộc (ví dụ: Message Queuing, trên đó Message Queuing Triggers phụ thuộc hoặc IIS, trên đó FTP PublishingWorld Wide Web Publishing phụ thuộc). Các mmc snap-in hiện này automagically, nhưng mã dường như không cung cấp các chức năng tương tự (ít nhất là không dễ dàng).Khởi động lại dịch vụ với các dịch vụ phụ thuộc?

MSDN documentation for Stop nói "Nếu bất kỳ dịch vụ nào phụ thuộc vào dịch vụ này cho hoạt động của họ, chúng sẽ bị ngừng trước khi dịch vụ này bị dừng. Thuộc tính DependentServices chứa tập hợp dịch vụ phụ thuộc vào dịch vụ này" và DependentServices trả về một loạt dịch vụ . Giả sử StartService()StopService() theo các công ước nêu trong các ví dụ và ví dụ tham chiếu ở trên (ngoại trừ việc họ chấp nhận ServiceControllersTimeSpans trực tiếp), tôi bắt đầu với:

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

Nhưng nếu sự phụ thuộc dịch vụ được lồng nhau (đệ quy) hoặc theo chu kỳ (nếu đó là thậm chí có thể ...) - nếu Service Aphụ thuộc vào bởi Service B1Service B2Service C1phụ thuộc vàoService B1, có vẻ như 'khởi động lại' Service A bằng phương pháp này sẽ dừng lại Service C1 nhưng sẽ không khởi động lại nó ...

Để làm ví dụ này hình ảnh rõ ràng hơn, tôi sẽ làm theo các mô hình trong mmc dịch vụ snap-in:

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

Có cách nào tốt hơn để đi về điều này, hoặc nó sẽ chỉ phải đệ quy bước vào và ngừng mỗi dịch vụ phụ thuộc và sau đó khởi động lại tất cả sau khi nó khởi động lại dịch vụ chính?

Ngoài ra, sẽ phụ thuộc nhưng hiện đang dừng các dịch vụ được liệt kê trong Dịch vụ phụ thuộc? Nếu vậy, điều này sẽ không khởi động lại chúng dù sao? Nếu vậy, chúng ta có nên kiểm soát điều đó không? Điều này dường như trở nên lộn xộn và phức tạp hơn ...

* Lưu ý: Tôi nhận thấy rằng timeout không được áp dụng chính xác ở đây (thời gian chờ tổng thể có thể dài hơn nhiều lần so với dự kiến), nhưng hiện tại không phải là vấn đề Tôi quan tâm - nếu bạn muốn sửa chữa nó, tốt, nhưng không chỉ nói 'thời gian chờ bị hỏng ...'

Cập nhật: Sau khi kiểm tra sơ bộ, tôi đã phát hiện (/ xác nhận) các hành vi sau:

  • Dừng dịch vụ (ví dụ: Service A) các dịch vụ khác (e .g. Service B1) phụ thuộc vào sẽ ngừng các dịch vụ khác (kể cả phụ thuộc "lồng" như Service C1)
  • DependentServiceskhông bao gồm dịch vụ phụ thuộc vào tất cả các nước (Chạy, Ngưng, vv), và nó cũng bao gồm phụ thuộc lồng nhau, ví dụ:Service_A.DependentServices sẽ chứa {Service B1, Service C1, Service B2} (theo thứ tự đó, như C1 phụ thuộc vào B1).
  • Bắt đầu dịch vụ phụ thuộc vào những dịch vụ khác (ví dụ: Service B1phụ thuộc vàoService A) cũng sẽ bắt đầu các dịch vụ cần thiết.

Đoạn mã trên do đó có thể được đơn giản hóa (ít nhất là một phần) để chỉ dừng dịch vụ chính (mà sẽ ngừng tất cả các dịch vụ phụ thuộc) và sau đó khởi động lại dịch vụ hầu hết phụ thuộc (ví dụ Service C1Service B2) (hoặc chỉ cần khởi động lại "tất cả" các dịch vụ phụ thuộc - nó sẽ bỏ qua những dịch vụ đã bắt đầu), nhưng điều đó thực sự chỉ ngăn cản sự khởi đầu của dịch vụ chính trong giây lát cho đến khi một trong những phụ thuộc phàn nàn về nó, vì vậy điều đó không thực sự hữu ích.

Trông bây giờ như chỉ khởi động lại tất cả các phụ thuộc là cách đơn giản nhất, nhưng mà bỏ qua (bây giờ) quản lý dịch vụ mà đã dừng lại và như vậy ...

Trả lời

4

Được rồi, cuối cùng đã triển khai điều này. Tôi đã đăng nó như là một câu trả lời riêng biệt như tôi đã đi đến kết luận này trong bản cập nhật ban đầu cho câu hỏi của tôi, mà đã được đăng trước câu trả lời đầu tiên.

Một lần nữa, StartService(), StopService()RestartService() phương pháp theo các công ước nêu trong các ví dụ và như vậy đã được tham chiếu trong các câu hỏi riêng của mình (tức là họ quấn Start/Stop hành vi để tránh "đã bắt đầu/dừng" -Loại trường hợp ngoại lệ) với phụ lục rằng nếu Service được chuyển vào (như trường hợp bên dưới), thì Refresh() được gọi trên dịch vụ đó trước khi kiểm tra Status của nó.

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

Nhận xét "trạng thái trước đó của họ là pres erved trong bộ sưu tập "không hợp lệ. Trạng thái dường như được cập nhật khi tôi thực thi mã này. Vì vậy, tôi đã phải sửa đổi nó để ghi lại tình trạng ban đầu trước khi khởi động lại dịch vụ chính. Có thể triển khai nội bộ .NET đã thay đổi kể từ khi bài đăng này được đăng? – Stif

1

Có vẻ như bạn muốn khởi động lại một "cơ sở "dịch vụ và có tất cả những thứ dựa vào nó cũng được khởi động lại. Nếu vậy, bạn không thể chỉ khởi động lại tất cả các dịch vụ phụ thuộc, vì chúng có thể không chạy trước. Không có API cho điều này mà tôi biết.

Cách tôi làm là viết một hàm đệ quy để quét tất cả các dịch vụ phụ thuộc (và phụ thuộc của chúng) và thêm tất cả các dịch vụ đang chạy vào danh sách theo thứ tự.

Khi bạn khởi động lại dịch vụ cơ sở, bạn có thể chỉ cần chạy qua danh sách này và bắt đầu mọi thứ. Miễn là bạn chưa sắp xếp lại danh sách, các dịch vụ sẽ bắt đầu theo đúng thứ tự và tất cả sẽ tốt.

+0

Yeah, đó là kết luận tôi đã giải quyết trên cũng không ... Nó không quá khó khăn, nó phức tạp hơn so với mmc - oh, well ... :) – johnny

+0

Và hóa ra nó không cần phải đệ quy - lưu ý (từ bản cập nhật của tôi) nhận được sự phụ thuộc trên một danh sách cơ sở _all_ dịch vụ phụ thuộc theo thứ tự phụ thuộc của họ, vì vậy bạn chỉ cần lọc danh sách đó cho những người đang thực sự chạy trước khi bạn khởi động lại cơ sở ... – johnny

1

Xin lưu ý dịch vụ 'phụ thuộc' rằng ServiceController.Stop() điểm dừng và ServiceController.Start() starts 'phụ thuộc vào' dịch vụ - như vậy, sau khi ngừng dịch vụ, bạn chỉ cần để bắt đầu dịch vụ mà là lá phụ thuộc của cây.

Giả sử không phụ thuộc cyclic được cho phép, các mã sau đây được dịch vụ mà cần phải được bắt đầu:

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

Và với một phương pháp đơn giản (ví dụphương pháp mở rộng):

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

Bạn chỉ có thể khởi động lại một dịch vụ:

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

điểm đáng chú ý:

Đối với mã clearity tôi không thêm:

  • thời gian chờ
  • kiểm tra lỗi

Xin lưu ý, đó là ứng dụng có thể kết thúc trong một trạng thái kỳ lạ, khi một số dịch vụ được khởi động lại và một số thì không ...

+0

Trong câu lệnh if của bạn, bạn cũng cần kiểm tra xem dịch vụ có đang chạy hay không trước khi thêm nó. if (! dependencyAdded &&! controllers.Contains (controller) && (controller.status! = ServiceControllerStatus.Stopped && controller.status! = ServiceControllerStatus.StopPending)) { bộ điều khiển.Thêm (bộ điều khiển); } – user398039

Các vấn đề liên quan