Anmutig Umgang Herunterfahren eines Windows-Dienstes
Davon ausgehen, dass Sie ein multi-threaded Windows service, der führt viele verschiedene Operationen, die einen fairen Anteil an Zeit, z.B. das extrahieren von Daten aus verschiedenen Daten speichert, analysieren diese Daten, die Entsendung von einem externen server etc. Operationen können durchgeführt werden, in verschiedenen Schichten, z.B. Anwendung, layer -, repository-Schicht-oder service-Schicht.
Irgendwann in die Lebensdauer dieser Windows-Dienst möchten Sie vielleicht, um es Herunterfahren oder neu starten, es durch Dienstleistungen.msc, aber wenn Sie nicht aufhören können, sind alle Operationen und beenden alle threads im Windows-Dienste innerhalb der Zeitspanne, die Dienstleistungen.msc erwartet, dass dies mit der stop-Prozedur, Sie werden hängen, und Sie müssen, um es zu töten mit dem Task-Manager.
Wegen der Frage oben erwähnt, meine Frage lautet wie folgt: Wie würden Sie implementieren eine fail-safe-Weg zum Umgang mit dem Herunterfahren Ihres Windows-Dienst? Ich habe eine volatile boolean, das wirkt wie ein shutdown-signal, aktiviert durch OnStop() in meinem service-Basis-Klasse, und sollte würdevoll halt meine main-Schleife, aber das ist nicht nichts Wert, wenn es eine operation, in einigen anderen Schicht, die unter, es ist Zeit, zu tun, was Sie, dass der Betrieb in der Lage ist.
Wie soll das gehandhabt werden? Ich bin momentan ratlos und brauche etwas kreativen input.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich mit einem
CancellationTokenSource
und propagieren die Stornierung token aus derOnStop
Methode unten, um alle Ebenen und alle threads und tasks gestartet. Es ist im Rahmen, so dass es wird nicht unterbrechen Sie Ihre lose Kopplung wenn Sie das interessieren (ich meine, überall dort, wo Sie einen thread/Task, die Sie auch haben "CancellationToken" zur Verfügung.Bedeutet dies, dass Sie anpassen müssen, async-Methoden zu nehmen Sie die Stornierung token in Betracht.
Sollten Sie sich auch bewusst sein,
ServiceBase.RequestAdditionalTime
. In Fall ist es nicht möglich zu stornieren, alle Aufgaben rechtzeitig, Sie können verlangen, eine Nachfrist.Alternativ vielleicht erkunden Sie die
IsBackground
alternative. Alle threads, die in Ihrem windows-Dienst, der aktiviert werden angehalten, durch die CLR, wenn Sie den Prozess beenden:Thread
direkt oderTask
/async/await.Nach mehr Forschung und einigem nachdenken kam ich zu erkennen, dass die Probleme, die ich bisher erlebt wurden verursacht durch eine sehr häufige design-Fehler in Bezug auf threads in Windows-Dienste.
Die Konstruktionsfehler
Stellen Sie sich vor Sie haben ein Gewinde, die nicht alle Ihre Arbeit. Ihre Arbeit besteht aus Aufgaben, die ausgeführt werden soll wieder und wieder auf unbestimmte Zeit. Dies ist oft wie folgt implementiert:
Dies ist die sehr häufige design Fehler, die ich erwähnt. Das problem ist, dass während dieser wird kompiliert und ausgeführt, wie erwarteten, werden Sie schließlich erleben, dass Ihr Windows-Dienst reagiert nicht auf die Befehle der service-Konsole in Windows. Dieses ist, weil Ihre Aufruf-Thread.Sleep() blockiert den thread, dass Ihr Dienst nicht mehr reagiert. Sie wird nur auftreten dieses Fehlers, wenn der thread-Blöcke länger als der timeout konfiguriert, die von Windows HKLM\SYSTEM\CurrentControlSet\Control\WaitToKillServiceTimeout, weil dieser registry-Wert, den diese Umsetzung kann für Sie arbeiten, wenn dein thread ist konfiguriert, um zu schlafen für eine sehr kurze Zeit, und es ist das arbeiten in einer akzeptablen Zeit.
Die alternative
Anstelle von Thread.Sleep() habe ich beschlossen zu gehen für ManualResetEvent und System.Threading.Timer statt. Die Umsetzung sieht wie folgt aus:
OnStart:
Callback:
OnStop:
Abschluss
Durch die Implementierung von System.Threading.Timer und ManualResetEvent vermeiden Sie, dass Ihr Dienst immer nicht mehr auf die service console-Befehle als Ergebnis des Threads.Sleep() blockiert.
PS! Sie dürfen nicht aus dem Wald nur noch!
Ich glaube jedoch, es gibt Fälle, in denen ein callback zugeordnet ist, so viel Arbeit, die durch den Programmierer, dass der Dienst nicht mehr reagiert werden, um service-console-Befehle während der workload-Ausführung. Wenn das passiert, können Sie wünschen zu betrachten, alternative Lösungen, wie Sie die überprüfung Ihrer ManualResetEvent tiefer in Ihrem code, oder vielleicht der Umsetzung CancellationTokenSource.