Quelle est la bonne façon pour un service Windows à l'échec?
J'ai hérité d'un service Windows écrit en C#. Dans de rares cas, il va mal. Cependant, il n'est pas clair du tout comment l'échec de bien. Ross Bennett états le problème élégamment à bytes.com. Par souci de simplicité, je vais juste citer ici.
Ohé, Les Gens!
J'ai cherché partout, pour cela,
mais je n'arrive pas à les secouer un
la documentation de la MSDN ou de
Google. J'ai passé en revue tous les .NET
article sur le développement de Services de Windows
dans la MSDN j'ai trouve.Je suis le développement d'un Service Windows
application. Ce service de son lit
les données de configuration du système
registre (HKLM) où il a été déposé
par un autre "gestionnaire" de l'application. Pas de
problèmes là-bas.Le service utilise un thread de travail à faire
ses travaux. Le thread est créé dans le
OnStart() et a/joint/cédées
dans le OnStop(). Encore une fois, pas de problèmes.Tout fonctionne à merveille lorsque:
- L'administrateur système a tout mettre en place correctement, et
- l'étranger les ressources du réseau sont tous accessibles.
Mais bien sûr, nous, en tant que développeurs tout simplement
ne pouvez pas compter sur:
- L'administrateur système ayant tout mis en place correctement, ou
- l'étranger les ressources du réseau accessible.
Vraiment, ce que nous avons besoin est pour la
application de service à certains
de mourir sur son propre. Si un réseau
des ressources tombe en panne, nous avons besoin de l'
arrêt du service. Mais plus de la
point, nous avons besoin de la SCM à savoir qu'il a
arrêté sur son propre accord. SCM besoins
à savoir que le service a
"a échoué"...et n'a pas simplement été fermé
par quelqu'un.L'appel de "retour" ou de jeter un
exception dans le "OnStart()" méthode
n'est même pas utile pour les services encore
dans le processus de démarrage.. Le SCM va
gaiement sur et le processus continue
cours d'exécution dans le Gestionnaire des Tâches--si
ce n'est pas en train de faire quoi que ce soit depuis
le thread de travail n'a jamais été créé
et a commencé.À l'aide d'un ServiceController exemple
ne pas le faire, soit. Qui semble
le SCM comme un arrêt normal, et non pas une
défaillance de service. Aucun
les mesures de rétablissement ou de redémarrage de se produire.
(Aussi, il est MSDNful documentation
avertissement sur les dangers d'un
ServiceBase descendant à l'aide d'un
ServiceController pour rendre les choses
arriver avec lui-même.)J'ai lu des articles où les gens ont été
bricoler avec PInvoking appels à
le code natif pour le
"Arrêté" de l'indicateur d'état dans le SCM. Mais
cela ne veut pas arrêter le processus de la
le service est en cours d'exécution à l'intérieur.J'aimerais vraiment connaître la Destinée
De:
- La fermeture d'un service à partir de l'intérieur du service, là où
- La SCM est appropriatedly averti que le service est "Stoppée", et
- Le processus disparaît à partir du Gestionnaire des Tâches.
Solutions impliquant ServiceControllers
ne semble pas être le cas, si seulement
parce que 2 n'est pas satisfait. (Que l'
Cadre de la documentation spécifiquement
contraindicates faire qui porte un
beaucoup de poids, d'ailleurs.)Je vous en serais reconnaissant de toutes les recommandations,
des pointeurs vers des documents ou même
raisonnée des conjectures. 🙂 Oh! Et
Je suis parfaitement heureux daccueillir que
J'ai manqué le point.Très cordialement,
Ross Bennett
Vous devez vous connecter pour publier un commentaire.
Les meilleures pratiques dans le code natif est d'appeler SetServiceStatus avec un code de sortie non nulle pour indiquer 1), il est arrêté et 2) quelque chose s'est mal passé.
En code managé, vous pourriez obtenir le même effet par l'obtention de la SCM de traiter dans le cadre le ServiceBase.ServiceHandle Propriété et de P/Invoke-ing de l'API Win32.
Je ne vois pas pourquoi la SCM traitera différemment de réglage de la
ServiceBase.ExitCode
propriété non-nul, et puis l'appel deServiceBase.Stop
, en fait. P/Invoke est un peu plus direct, peut-être, si le service est en mode panique.Environment.Exit()
ou de lancer une exception et ne pas attraper la cause de la "anormale" de la résiliation que le système d'exploitation semble être à la recherche pour les, pour les auto-restart-sur-échec.J'ai trouvé que l'Environnement.Exit(1) fonctionne très bien pour moi. En général, je le place dans une méthode qui attrape les exceptions non gérées et du journal le problème avant de m'arrêter. Il détruit complètement le service, mais la SCM sait aussi qu'il est à l'arrêt. Vous pouvez définir la SCM pour redémarrer votre service automatiquement quand il descend x nombre de fois. Je trouve que c'est beaucoup plus utile que de l'écriture de votre propre redémarrage/arrêt de code.
Je ne sais pas si il y a une (non-P/Invoke) équivalent à cela, mais la WinAPI voie semble être d'appeler
SetServiceStatus
avec une valeur deSERVICE_STOPPED
et puis d'attendre pour le SCM pour vous arrêtez vers le bas. Comme un effet secondaire positif, il enregistre l'échec de votre service dans le journal des événements.Voici quelques citations de la partie pertinente de la documentation:
PS: À mon avis, si les ressources du réseau sont pas disponibles, le service ne doit pas s'arrêter, mais continue de fonctionner, d'attente pour les ressources deviennent disponibles. Temporaire du réseau coupures de courant peuvent se produire, et ils ne devraient pas nécessiter d'intervention manuelle de l'administrateur système une fois que le réseau est de retour.
Vous pouvez obtenir la bonne ExitCode comme décrit ici.
Si le Gestionnaire de Services Windows donnera le droit a l'erreur de texte.
Mon Démarrage dans ServiceBase ressemble à ceci:
Après quelques tests, j'ai trouvé les ouvrages suivants, dans le cas où vous appeler Arrêt peut provoquer d'autres problèmes:
Juste appeler de l'Environnement.La sortie n'est pas faire de la SCM n'gestion des pannes, mais d'abord le réglage de la ServiceBase ExitCode n'.