2013-08-06 15 views
8

Mam niektóre usługi Windows, które napisałem w Delphi i ogólnie działają bardzo dobrze, jednak czasami otrzymuję wyjątek, który można uznać za śmiertelny. Kiedy tak się dzieje, usługa ma się zatrzymać.Jak uzyskać system Windows SCM, aby ponownie uruchomić moją usługę, gdy się zawiedzie

Moje pytanie brzmi: jak wyjść z usługi w taki sposób, że SCM automatycznie spróbuje ponownie uruchomić usługę. (Mam już ustawione opcje odzyskiwania dla usługi w menedżerze usług)

MSDN stany

Usługa jest uważany zawiodły, gdy kończy się bez raportowania statusu SERVICE_STOPPED do kontrolera sieci.

czytałem tę blogu Using the Automatic Recovery Features of Windows Services ale nie jestem pewien, jak zaimplementować to w Delphi.

mam allready próbowała następujące

  • Ustawianie ErrCode własność TService do nieprzestrzegania wartości zerowej.
  • Ustawienie zatrzymanego parametru zdarzenia ServiceStop na wartość false.
  • Zgłaszanie wyjątku w procedurze obsługi zdarzeń servicestop.

EDIT 06.08.2013 dodany przykład kodu

Kodeks zaktualizowany, aby pokazać przykład roboczych

Oto kod IM stosując

procedure TTestService.ServiceExecute(Sender: TService); 
begin 

    while not (Terminated or FFatalError) do 
    begin 
    ServiceThread.ProcessRequests(False); 
    ReportStatus; 
    Sleep(100); 
    end; 

    if FFatalError then 
    Halt(1); 

end; 

FFatalError jest prywatnym boolowskim polem na klasie TTestService i jest zainicjalizowane Wartość false podczas uruchamiania jest ustawiona na wartość true tylko wtedy, gdy wątek roboczy (uruchomiony w zdarzeniu TTestService.ServiceStart) kończy się z krytycznym wyjątkiem.

Tutaj znajduje się procedura obsługi zdarzenia OnTerminate dla wątku roboczego.

procedure TTestService.ThdTerm(Sender: Tobject); 
var 
    E : Exception; 
    Thread : TThread; 
begin 
    Thread := TThread(Sender); 

    if (Thread.FatalException <> nil) then 
    begin 
    E := Exception(Thread.FatalException); 
    GetExcCallStack(E); 

    EventLog.LogError(Thread.ClassName + ': ID:'+ IntToStr(Thread.ThreadID) + 
     ' Stopped Unexpectedly!, '+ NEWLINE + E.ClassName +': ' + E.Message); 
    FFatalError := True; 
    end; 

end; 
+0

Czy próbowałeś wywołać 'ExitProcess'? –

+0

"Kiedy to się dzieje, usługa jest przeznaczona do zatrzymania." To może być problem.Być może trzeba będzie wybrać sposób obsługi wyjątku lub pozwolić mu naprawdę zawieść. Być może, jeśli opublikujesz kod, który "ma na celu zatrzymanie" usługi, być może będziemy mogli widzieć jaśniej. – Sam

+0

Wystarczy przerwać proces serwisowy za pomocą Menedżera zadań. Jeśli SCM restart config dla twojej usługi jest poprawny, usługa zostanie uruchomiona ponownie. – Alexandr

Odpowiedz

8

SCM zrestartuje usługę, jeśli się nie powiedzie. Ale wszystkie normalne tryby zakończenia z usługi Delphi nie są liczone jako niepowodzenie. Jeśli mógłbyś zgłosić wyjątek od głównego wątku serwisowego, który był nieobsługiwany, wtedy byłby to traktowany jako niepowodzenie.

Jednak uważam, że najprostszym sposobem wymuszenia zakończenia procesu traktowanego jako awaria jest wywołanie ExitProcess. Równie dobrze można zadzwonić do funkcji Delphi RTL Halt, która ostatecznie zadzwoni pod numer ExitProcess. Jednakże, ponieważ Twój proces prawdopodobnie jest w złym stanie, byłbym skłonny przejść bezpośrednio do ExitProcess.

Jak już wspomniano, unikanie wyjątku w pierwszej kolejności byłoby idealnym rozwiązaniem.

+1

jitenable może pomóc. –

+0

Dziękuję za pomoc. Mam teraz działający i zaktualizowałem kod w pytaniu, aby pokazać moje rozwiązanie – MikeT

Powiązane problemy