Ich muss robusten Code in .NET schreiben, damit ein Windows-Dienst (Server 2003) sich selbst neu starten kann. Was ist der beste Weg dazu? Gibt es eine .NET-API dafür?
Ich muss robusten Code in .NET schreiben, damit ein Windows-Dienst (Server 2003) sich selbst neu starten kann. Was ist der beste Weg dazu? Gibt es eine .NET-API dafür?
Antworten:
Stellen Sie den Dienst so ein, dass er nach einem Fehler neu gestartet wird (doppelklicken Sie auf den Dienst in der Systemsteuerung und sehen Sie sich auf diesen Registerkarten um - ich habe den Namen vergessen). Wenn Sie dann möchten, dass der Dienst neu gestartet wird, rufen Sie einfach an Environment.Exit(1)
(oder eine Rückgabe ungleich Null), und das Betriebssystem startet ihn für Sie neu.
Service.ExitCode = 1
und dann ausführen Service.Stop()
. Wenn Sie dies auf diese Weise tun, wird das System ordnungsgemäß heruntergefahren und der Neustart ausgelöst.
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()
Sie können nicht sicher sein, ob das Benutzerkonto, unter dem Ihr Dienst ausgeführt wird, überhaupt die Berechtigung hat, den Dienst zu stoppen und neu zu starten.
Sie können einen Prozess erstellen, bei dem es sich um eine DOS-Eingabeaufforderung handelt, die sich selbst neu startet:
Process process = new Process();
process.StartInfo.FileName = "cmd";
process.StartInfo.Arguments = "/c net stop \"servicename\" & net start \"servicename\"";
process.Start();
const string strCmdText = "/C net stop \"SERVICENAME\"&net start \"SERVICENAME\"";
Process.Start("CMD.exe", strCmdText);
Wo SERVICENAME
ist der Name Ihres Dienstes (doppelte Anführungszeichen, um Leerzeichen im Dienstnamen zu berücksichtigen, können ansonsten weggelassen werden).
Sauber, keine automatische Neustartkonfiguration erforderlich.
Es hängt davon ab, warum Sie möchten, dass es sich selbst neu startet.
Wenn Sie nur nach einer Möglichkeit suchen, den Dienst regelmäßig selbst zu bereinigen, wird möglicherweise ein Timer im Dienst ausgeführt, der regelmäßig eine Bereinigungsroutine verursacht.
Wenn Sie nach einer Möglichkeit suchen, bei einem Fehler neu zu starten, kann der Service-Host diese Funktion beim Einrichten bereitstellen.
Warum müssen Sie den Server neu starten? Was versuchst du zu erreichen?
Ich glaube nicht, dass Sie dies in einem eigenständigen Dienst tun können (wenn Sie Restart aufrufen, wird der Dienst gestoppt, wodurch der Befehl Restart unterbrochen wird und er wird nie wieder gestartet). Wenn Sie eine zweite EXE-Datei hinzufügen können (eine Konsolen-App, die die ServiceManager-Klasse verwendet), können Sie die eigenständige EXE-Datei starten, den Dienst neu starten und dann beenden.
Beim zweiten Gedanken könnte der Dienst wahrscheinlich eine geplante Aufgabe registrieren lassen (z. B. über den Befehlszeilenbefehl 'at'), um den Dienst zu starten und ihn dann selbst stoppen zu lassen. das würde wahrscheinlich funktionieren.
Das Problem beim Auslagern in eine Batchdatei oder EXE besteht darin, dass ein Dienst möglicherweise über die zum Ausführen der externen App erforderlichen Berechtigungen verfügt oder nicht.
Der sauberste Weg, dies zu tun, ist die OnStop () -Methode, die der Einstiegspunkt für den Service Control Manager ist. Dann wird Ihr gesamter Bereinigungscode ausgeführt, und Sie haben keine hängenden Sockets oder andere Prozesse, vorausgesetzt, Ihr Stoppcode erledigt seine Aufgabe.
Dazu müssen Sie vor dem Beenden ein Flag setzen, das die OnStop-Methode anweist, mit einem Fehlercode zu beenden. dann weiß der SCM, dass der Dienst neu gestartet werden muss. Ohne dieses Flag können Sie den Dienst nicht manuell vom SCM aus stoppen. Dies setzt auch voraus, dass Sie den Dienst so eingerichtet haben, dass er bei einem Fehler neu gestartet wird.
Hier ist mein Stoppcode:
...
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);
}
Wenn der Dienst auf ein Problem stößt und neu gestartet werden muss, starte ich einen Thread, der den Dienst vom SCM stoppt. Dies ermöglicht es dem Dienst, nach sich selbst aufzuräumen:
...
if(NeedToRestart)
{
ABORT = true;
new Thread(RestartThread).Start();
}
void RestartThread()
{
ServiceController sc = new ServiceController(ServiceName);
try
{
sc.Stop();
}
catch (Exception) { }
}
Ich würde den Windows Scheduler verwenden, um einen Neustart Ihres Dienstes zu planen. Das Problem ist, dass Sie sich nicht neu starten können, aber Sie können sich selbst stoppen. (Sie haben im Wesentlichen den Ast abgesägt, auf dem Sie sitzen ... wenn Sie meine Analogie verstehen.) Sie benötigen einen separaten Prozess, um dies für Sie zu tun. Der Windows Scheduler ist geeignet. Planen Sie eine einmalige Aufgabe, um Ihren Dienst (auch innerhalb des Dienstes selbst) neu zu starten und sofort auszuführen.
Andernfalls müssen Sie einen "Hirten" -Prozess erstellen, der dies für Sie erledigt.
Die erste Antwort auf die Frage ist die einfachste Lösung: "Environment.Exit (1)" Ich verwende dies unter Windows Server 2008 R2 und es funktioniert perfekt. Der Dienst stoppt sich selbst, das Betriebssystem wartet 1 Minute und startet es dann neu.
Der bessere Ansatz könnte darin bestehen, den NT-Dienst als Wrapper für Ihre Anwendung zu verwenden. Wenn der NT-Dienst gestartet wird, kann Ihre Anwendung in einem "Leerlauf" -Modus gestartet werden, der auf den Start des Befehls wartet (oder so konfiguriert sein, dass er automatisch gestartet wird).
Denken Sie an ein Auto, wenn es gestartet wird, beginnt es im Leerlauf und wartet darauf, dass Ihr Befehl vorwärts oder rückwärts geht. Dies bietet auch andere Vorteile, z. B. eine bessere Remoteverwaltung, da Sie auswählen können, wie Ihre Anwendung verfügbar gemacht werden soll.
Gerade vorbei: und dachte, ich würde ein paar zusätzliche Informationen hinzufügen ...
Sie können auch eine Ausnahme auslösen. Dadurch wird der Windows-Dienst automatisch geschlossen, und die Optionen für den automatischen Neustart werden aktiviert. Das einzige Problem dabei ist, dass die JIT versucht, den PC einzuschalten, wenn Sie eine Entwicklungsumgebung auf Ihrem PC haben. und Sie erhalten eine Eingabeaufforderung mit der Meldung Debug J / N. Sagen Sie Nein, und dann wird es geschlossen und dann ordnungsgemäß neu gestartet. (Auf einem PC ohne JIT funktioniert einfach alles). Der Grund für das Trolling ist, dass diese JIT neu in Win 7 ist (sie funktionierte früher einwandfrei mit XP usw.) und ich versuche, eine Möglichkeit zu finden, die JIT zu deaktivieren. Ich kann die hier erwähnte Environment.Exit-Methode ausprobieren das funktioniert auch
Kristian: Bristol, Großbritannien
Erstellen Sie eine restart.bat-Datei wie diese
@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%
Löschen Sie dann die Aufgabe% taskname%, wenn Ihr% service% gestartet wird
Erstellen Sie eine separate Appdomain, um den Anwendungscode zu hosten. Wenn ein Neustart erforderlich ist, können wir die App-Domäne anstelle des Prozesses (Windows-Dienst) entladen und neu laden. So funktioniert der IIS-App-Pool. Sie führen die asp.net-App nicht direkt aus, sondern verwenden einen separaten Appdmain.
Am einfachsten ist es, eine Batch-Datei zu haben mit:
net stop net start
und fügen Sie die Datei mit dem gewünschten Zeitintervall zum Scheduler hinzu
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();
}
}