W jaki sposób usługa systemu Windows może się programowo zrestartować?

Odpowiedzi:

187

Ustaw usługę na restart po awarii (dwukrotnie kliknij usługę w panelu sterowania i rozejrzyj się po tych zakładkach - zapomniałem jej nazwy). Następnie, za każdym razem, gdy chcesz, aby usługa została ponownie uruchomiona, po prostu zadzwoń Environment.Exit(1)(lub jakikolwiek zwrot niezerowy), a system operacyjny zrestartuje ją za Ciebie.

TheSoftwareJedi
źródło
7
Fyi lokalizacja znajduje się w panelu usług, kliknij prawym przyciskiem myszy daną usługę i wybierz właściwości, a następnie wybierz kartę odzyskiwania.
James Michael Hare
20
Widzę, jak to zapewnia pożądane zachowanie, ale kod powrotu o wartości 1 ma na celu poinformowanie systemu, że wystąpił błąd. Czy nie jest to zła praktyka, jeśli w rzeczywistości nie było błędu, a po prostu chciałeś ponownie uruchomić usługę?
mgttlinger
4
Można to zrobić programowo przez instalatora usługi w zdarzeniu po instalacji, bez potrzeby klikania ... A co, jeśli Twoja usługa znajduje się na zdalnym serwerze i musisz ją instalować kilka razy dziennie, na przykład podczas testowania?
Dean Kuga
5
@mgttlinger: Myślę, że tak, to zła praktyka, gdy twoja usługa jest sprawna, więc nigdy nie będzie trzeba jej ponownie uruchamiać. Jednak niektóre architektury usług są poza naszym zasięgiem i jeśli trzeba je zrestartować, to oznaka, że ​​nie jest dobrze, więc nie ma problemu z zamknięciem i zwolnieniem niektórych minimalnych zasobów (jeśli to możliwe) i `` obcięciem nóg '', ponieważ opuszczenie usługa działająca nieprawidłowo może być gorsza (bezużyteczna).
Luciano,
5
@JohnLeidegren, jeśli chcesz poprawnie wyłączyć, możesz ustawić, Service.ExitCode = 1a następnie wykonać Service.Stop()wraz z zaznaczeniem pola wyboru „Włącz akcje dla zatrzymań z błędami” na ekranie ustawień odzyskiwania usługi. Zrobienie tego w ten sposób pozwala na prawidłowe zamknięcie i nadal powoduje ponowne uruchomienie.
Chris Rice
22
Dim proc As New Process()
Dim psi As New ProcessStartInfo()

psi.CreateNoWindow = True
psi.FileName = "cmd.exe"
psi.Arguments = "/C net stop YOURSERVICENAMEHERE && net start YOURSERVICENAMEHERE"
psi.LoadUserProfile = False
psi.UseShellExecute = False
psi.WindowStyle = ProcessWindowStyle.Hidden
proc.StartInfo = psi
proc.Start()
Khalid Rahaman
źródło
3
Pamiętaj, aby dodać „” wokół nazwy usługi, jeśli zawiera spacje.
apc
4
Dotyczy to tylko usług działających na koncie uprzywilejowanym, co i tak jest złym pomysłem.
Dmitry Gusarov
17

Nie możesz być pewien, że konto użytkownika, na którym działa Twoja usługa, ma nawet uprawnienia do zatrzymywania i ponownego uruchamiania usługi.

Greg Hewgill
źródło
Chociaż + 1-ed, gdy napotkałem ten sam problem, patrząc na sc.exe okazuje się, że używa SERVICE_QUERY_CONFIG jako dwDesiredAccess podczas wywoływania OpenSCManager (), a następnie wywołuje OpenService () z SERVICE_START | SERVICE_STOP, aby otworzyć określoną usługę i działa OK (nie ma problemu z dostępem). Nie jestem pewien, jak można to zrobić w .NET.
n0p
Większość usług Windows działa jako system, więc nie powinno to stanowić problemu.
Przełącz
@Switch istnieje ogromny krąg usług, które są uruchamiane w ramach USŁUGI SIECIOWEJ, która domyślnie nie ma nawet uprawnień do otwierania własnego pliku wykonywalnego.
AgentFire
@AgentFire, poprawna, ale domyślna to Local System, a nie NETWORK SERVICE. System lokalny ma z natury najwyższy poziom uprawnień do systemu operacyjnego - przewyższający te przypisane członkom lokalnej grupy Administratorzy.
Przełącz się
@Switch ale przy użyciu najbardziej dostępnych przywilejów jest naruszenie Pol-Principle .
AgentFire
12

Możesz utworzyć proces będący wierszem poleceń DOS, który uruchamia się ponownie:

 Process process = new Process();
 process.StartInfo.FileName = "cmd";
 process.StartInfo.Arguments = "/c net stop \"servicename\" & net start \"servicename\"";
 process.Start();
VladL
źródło
To bez robienia czegokolwiek innego odziedziczy kontekst bezpieczeństwa wątku wywołującego ... i jeśli jest to kontekst, który ma wystarczającą moc do ponownego uruchomienia, jesteś dobry.
Clay
12
const string strCmdText = "/C net stop \"SERVICENAME\"&net start \"SERVICENAME\"";
Process.Start("CMD.exe", strCmdText);

gdzie SERVICENAMEjest nazwą Twojej usługi (podwójne cudzysłowy uwzględniają spacje w nazwie usługi, w przeciwnym razie można pominąć).

Czysty, nie jest wymagana konfiguracja automatycznego restartu.

Filip
źródło
9
dowiedziałem się czegoś nowego o & vs &&: [polecenie1] & [polecenie2] zawsze wykona oba polecenia sekwencyjnie, podczas gdy [polecenie1] && [polecenie2] uruchomi polecenie2 tylko wtedy, gdy polecenie1 zostanie uruchomione pomyślnie ( autoitscript.com/forum/topic/ ... )
Jeffrey Knight
5

Zależałoby to od tego, dlaczego chcesz, aby sam się zrestartował.

Jeśli szukasz tylko sposobu na okresowe czyszczenie usługi, możesz mieć uruchomiony licznik czasu w usłudze, który okresowo powoduje procedurę czyszczenia.

Jeśli szukasz sposobu na ponowne uruchomienie w przypadku awarii - sam host usługi może zapewnić tę możliwość podczas konfiguracji.

Dlaczego więc musisz restartować serwer? Co próbujesz osiągnąć?

Brody
źródło
1
To nie zadziała, jeśli martwisz się o stertę dużych obiektów i fragmentację pamięci. Podobno procesy .NET 4 / 4.5 i 64-bitowe bardzo w tym pomogły.
David Kassa,
3

Nie sądzę, abyś mógł w samodzielnej usłudze (gdy zadzwonisz do Restart, zatrzyma usługę, co przerwie polecenie Restart i nigdy więcej nie zostanie uruchomione). Jeśli możesz dodać drugi plik .exe (aplikację konsoli, która używa klasy ServiceManager), możesz uruchomić autonomiczny plik .exe i uruchomić ponownie usługę, a następnie zakończyć.

Po namyśle prawdopodobnie mógłbyś poprosić usługę o zarejestrowanie zaplanowanego zadania (na przykład za pomocą polecenia „at” w wierszu poleceń), aby uruchomić usługę, a następnie spowodować jej zatrzymanie; to prawdopodobnie by zadziałało.

technofil
źródło
3

Problem z wyrzucaniem do pliku wsadowego lub pliku EXE polega na tym, że usługa może mieć uprawnienia wymagane do uruchomienia aplikacji zewnętrznej lub nie.

Najczystszym sposobem, jaki znalazłem, jest użycie metody OnStop (), która jest punktem wejścia dla Menedżera sterowania usługami. Wtedy cały kod czyszczący zostanie uruchomiony i nie będziesz mieć żadnych zawieszonych gniazd ani innych procesów, zakładając, że kod zatrzymujący wykonuje swoją pracę.

Aby to zrobić, musisz ustawić flagę przed zakończeniem, która mówi metodzie OnStop, aby zakończyła pracę z kodem błędu; wtedy SCM wie, że usługa wymaga ponownego uruchomienia. Bez tej flagi nie będzie można ręcznie zatrzymać usługi z poziomu SCM. Zakłada się również, że usługa została skonfigurowana do ponownego uruchamiania w przypadku błędu.

Oto mój kod zatrzymania:

...

bool ABORT;

protected override void OnStop()
{
    Logger.log("Stopping service");
    WorkThreadRun = false;
    WorkThread.Join();
    Logger.stop();
    // if there was a problem, set an exit error code
    // so the service manager will restart this
    if(ABORT)Environment.Exit(1);
}

Jeśli usługa napotka problem i musi zostać ponownie uruchomiona, uruchamiam wątek, który zatrzymuje usługę z SCM. Pozwala to usłudze posprzątać po sobie:

...

if(NeedToRestart)
{
    ABORT = true;
    new Thread(RestartThread).Start();
}

void RestartThread()
{
    ServiceController sc = new ServiceController(ServiceName);
    try
    {
        sc.Stop();
    }
    catch (Exception) { }
}
user3235770
źródło
2

Użyłbym harmonogramu systemu Windows do zaplanowania ponownego uruchomienia usługi. Problem polega na tym, że nie możesz się zrestartować, ale możesz się zatrzymać. (Zasadniczo odpiłowałeś gałąź, na której siedzisz ... jeśli masz moją analogię) Potrzebujesz oddzielnego procesu, aby zrobić to za siebie. Harmonogram systemu Windows jest odpowiedni. Zaplanuj jednorazowe zadanie ponownego uruchomienia usługi (nawet z poziomu samej usługi) w celu natychmiastowego wykonania.

W przeciwnym razie będziesz musiał stworzyć proces „pasterski”, który zrobi to za Ciebie.

dviljoen
źródło
2

Pierwszą odpowiedzią na pytanie jest najprostsze rozwiązanie: „Environment.Exit (1)” Używam tego na Windows Server 2008 R2 i działa idealnie. Usługa zatrzymuje się, system operacyjny czeka 1 minutę, a następnie uruchamia ją ponownie.

tangentMan
źródło
To, jak długo czeka, zależy od tego, jak długo zostało skonfigurowane. Domyślnie jest to 1 minuta, ale jeśli ktoś nie chce, aby Twoja odpowiedź sprawiła złe wrażenie.
Espen
1

Myślę, że nie może. Kiedy usługa zostaje „zatrzymana”, zostaje całkowicie rozładowana.

Cóż, OK, przypuszczam, że zawsze istnieje sposób. Na przykład możesz utworzyć odłączony proces, aby zatrzymać usługę, a następnie uruchomić ją ponownie, a następnie zakończyć.

PRZETRZĄSAĆ
źródło
0

Lepszym podejściem może być wykorzystanie usługi NT jako opakowania aplikacji. Po uruchomieniu usługi NT aplikacja może zostać uruchomiona w trybie „bezczynności”, czekając na uruchomienie polecenia (lub może zostać skonfigurowana do automatycznego uruchamiania).

Pomyśl o samochodzie, gdy jest uruchamiany, zaczyna się na biegu jałowym, czekając na polecenie ruchu do przodu lub do tyłu. Zapewnia to również inne korzyści, takie jak lepsza administracja zdalna, ponieważ możesz wybrać sposób udostępnienia aplikacji.

plamb
źródło
0

Tylko przekazuję: i pomyślałem, że dodam dodatkowe informacje ...

możesz również rzucić wyjątek, spowoduje to automatyczne zamknięcie usługi systemu Windows, a opcje automatycznego ponownego uruchomienia po prostu się włączy. Jedynym problemem jest to, że jeśli masz środowisko programistyczne na swoim komputerze, JIT próbuje się uruchomić, a pojawi się monit o debugowanie T / N. powiedz nie, a następnie zamknie się, a następnie uruchomi się ponownie. (na komputerze bez JIT wszystko działa). powodem, dla którego trolluję, jest to, że ten JIT jest nowy w Win 7 (działał dobrze z XP itp.) i próbuję znaleźć sposób na wyłączenie JIT ... mogę wypróbować wspomnianą tutaj metodę Environment.Exit zobacz jak to też działa.

Kristian: Bristol, Wielka Brytania

Kristian
źródło
3
Wszystkie te rozwiązania rzutowania wyjątków, exit (1) pozwalają uniknąć prawidłowego czyszczenia aplikacji.
Nieprzyjemne
0

Utwórz plik restart.bat w ten sposób

@echo on
set once="C:\Program Files\MyService\once.bat"
set taskname=Restart_MyService
set service=MyService
echo rem %time% >%once%
echo net stop %service% >>%once%
echo net start %service% >>%once%
echo del %once% >>%once%

schtasks /create /ru "System" /tn %taskname% /tr '%once%' /sc onstart /F /V1 /Z
schtasks /run /tn %taskname%

Następnie usuń zadanie% taskname% po uruchomieniu% service%

Erik Martino
źródło
0

Utwórz oddzielną domenę aplikacji do hostowania kodu aplikacji. Gdy wymaga ponownego uruchomienia, możemy zwolnić i ponownie załadować domenę aplikacji zamiast procesu (usługa Windows). W ten sposób działa pula aplikacji usług IIS, nie uruchamiają aplikacji asp.net bezpośrednio, używają oddzielnej aplikacji appdmain.

CreativeManix
źródło
-2

Najłatwiej jest mieć plik wsadowy zawierający:

net stop net start

i dodaj plik do harmonogramu z żądanym przedziałem czasu


źródło
To nie działa, ponieważ partia jest zatrzymywana między oboma poleceniami, ponieważ jest to proces potomny samej usługi.
Orabîg,
-3
private static void  RestartService(string serviceName)
    {
        using (var controller = new ServiceController(serviceName))
        {
            controller.Stop();
            int counter = 0;
            while (controller.Status != ServiceControllerStatus.Stopped)
            {
                Thread.Sleep(100);
                controller.Refresh();
                counter++;
                if (counter > 1000)
                {
                    throw new System.TimeoutException(string.Format("Could not stop service: {0}", Constants.Series6Service.WindowsServiceName));
                }
            }

            controller.Start();
        }
    }
Lee Smith
źródło