Le service Windows OnStop attend le traitement terminé
J'ai fait développer un service Windows dans visual studio 2012 /.NET 4.5.
Le service est suivant le schéma de l'extrait de code ci-dessous:
- L'aide d'une minuterie
- Exécute l'opération souhaitée toutes les deux minutes.
- Le processus prend environ 10 minutes
- - Je utiliser un seul fil dans le service
Ce que je suis inquiète, c'est que si quelqu'un arrête le service via la console de gestion, il pourrait être juste pendant le processus que le service est en train de faire.
J'ai fait un peu de lecture à propos de l'arrêt de Windows service avec demande d'arrêter, mais je suis un peu perdu. Parfois WorkerThreads sont créés, parfois ManualResetEvents sont créés, mais jusqu'à maintenant, je ne pouvais pas saisir pleinement la meilleure voie à suivre pour mon service Windows.
J'ai besoin d'attendre jusqu'à ce que le traitement est bien fini dans la méthode onStop avant d'arrêter le service Windows.
Quelle est la meilleure façon de l'avant, compte tenu également de l'extrait de code ci-dessous?
Merci à tous!
namespace ImportationCV
{
public partial class ImportationCV : ServiceBase
{
private System.Timers.Timer _oTimer;
public ImportationCV()
{
InitializeComponent();
if (!EventLog.SourceExists(DAL.Utilities.Constants.LOG_JOURNAL))
{
EventLog.CreateEventSource(DAL.Utilities.Constants.LOG_JOURNAL, DAL.Utilities.Constants.SOURCE_JOURNAL);
}
EventLog.Source = DAL.Utilities.Constants.SOURCE_JOURNAL;
EventLog.Log = DAL.Utilities.Constants.LOG_JOURNAL;
}
protected override void OnStart(string[] args)
{
int intDelai = Properties.Settings.Default.WatchDelay * 1000;
_oTimer = new System.Timers.Timer(intDelai);
_oTimer.Elapsed += new ElapsedEventHandler(this.Execute);
_oTimer.Start();
EventLog.WriteEntry(DAL.Utilities.Constants.LOG_JOURNAL, "Service " + DAL.Utilities.Constants.SERVICE_TITLE + " started at " + DateTime.Now.ToString("HH:mm:ss"), EventLogEntryType.Information);
}
protected override void OnStop()
{
if (_oTimer != null && _oTimer.Enabled)
{
_oTimer.Stop();
_oTimer.Dispose();
}
EventLog.WriteEntry(DAL.Utilities.Constants.LOG_JOURNAL, "Service " + DAL.Utilities.Constants.SERVICE_TITLE + " stopped at " + DateTime.Now.ToString("HH:mm:ss"), EventLogEntryType.Information);
}
private void Execute(object source, ElapsedEventArgs e)
{
_oTimer.Stop();
try
{
//Process
}
catch (Exception ex)
{
EventLog.WriteEntry(DAL.Utilities.Constants.LOG_JOURNAL, (ex.StackTrace + ("\r\n" + ex.Message)), EventLogEntryType.Error);
}
_oTimer.Start();
}
}
}
source d'informationauteur crisjax | 2014-03-20
Vous devez vous connecter pour publier un commentaire.
Comme un cas de test, j'ai mis un appel à
System.Threading.Thread.Sleep(500000)
dans leOnStop()
de rappel de mon service Windows. J'ai commencé le service, puis il s'est arrêté. J'ai eu la fenêtre avec la barre de progression indiquant que le Gestionnaire de Contrôle des Services (SCM), était de tenter d'arrêter le service. Après environ 2 minutes, j'ai reçu cette réponse de la SCM:Après, j'ai rejeté cette fenêtre, l'état de mon service dans le SCM changé à Arrêtet j'ai remarqué que le service a continué d'exécution dans le Gestionnaire des Tâches. Après le sommeil écoulé (près de 6 minutes plus tard), le processus s'est arrêté. L'actualisation de la SCM fenêtre a montré que le service n'était plus en cours d'exécution.
Je prends quelques choses à l'écart de ce. Tout d'abord,
OnStop()
devrait vraiment essayer d'arrêter le service en temps opportun, tout comme une partie de la jouer gentil avec le système. Deuxièmement, selon la façon dont votreOnStop()
méthode est structurée, vous pourrait force au service de l'ignorer préventive demande d'arrêter, au lieu de s'arrêter lorsque vous le dire. Ce n'est pas recommandé, mais il semble que vous pourrait ce faire.À votre situation particulière, la chose que vous devez comprendre, c'est que le
System.Timers.Timer.Elapsed
événement feux sur unpool de threads
thread. Par définition, c'est un thread d'arrière-plance qui signifie qu'il ne sera pas garder l'application en cours d'exécution. Lorsque le service est dit à l'arrêt, le système va s'arrêter tous les threads d'arrière-plan et puis la sortie du processus. Si votre préoccupation au sujet de l'observance du traitement d'aller jusqu'au bout en dépit d'être dit par la SCM à l'arrêt ne peut pas se produire de la manière que vous avez des choses structuré actuellement. Pour ce faire, vous devez créer un officielSystem.Threading.Thread
objet, de le définir comme un thread de premier plan, et ensuite utiliser la minuterie pour déclencher ce thread à exécuter (par opposition à fait dans laElapsed
de rappel).Tout ce qui est dit, je pense toujours que vous aurez envie de jouer gentiment avec le système, ce qui signifie en temps opportun de l'arrêt du service en font la demande. Qu'advient-il si, par exemple, vous avez besoin de redémarrer la machine? Je n'ai pas testé, mais si vous forcez votre service pour continuer à fonctionner jusqu'à ce que le traitement est terminé, le système peut en effet attendre la fin du processus avant de le redémarrer. Ce n'est pas ce que je veux de mon service.
Je vous suggère de deux choses l'une. La première option serait de séparer le traitement des différents morceaux qui peut être fait individuellement. Comme chaque bloc est terminé, vérifiez pour voir si le service est en cours d'arrêt. Si donc, exit le fil correctement. Si cela ne peut être fait, alors je voudrais introduire quelque chose qui s'apparente à des opérations de votre traitement. Disons que vous êtes d'avoir à interagir avec un tas de tables de base de données et l'interruption de l'écoulement une fois que c'est commencé devient problématique parce que la base de données peut être laissé dans un mauvais état. Si le système de base de données permet de transactions, il devient relativement facile. Si pas, alors ne tout le traitement vous pouvez en mémoire et valider les modifications apportées à la dernière seconde. De cette façon, vous n'bloc d'arrêter, tandis que les changements sont en train d'être commis par opposition à un blocage de l'ensemble de la durée. Et pour ce que ça vaut, je préfère utiliser
ManualResetEvent
pour communiquer des commandes d'arrêt aux threads.Pour éviter la divagation plus loin, je vais le couper ici. HTH.
EDIT:
C'est improvisé, donc je ne vais pas vérifier son exactitude. Je vais corriger tout problème que vous (ou d'autres) peuvent se trouver.
Définir deux
ManualResetEvent
objets, un pour la notification d'arrêt et l'autre pour le traitement de la notification et de laThread
objet. Modifier laOnStart()
rappel:Changer votre
Execute()
de rappel à quelque chose comme ceci:Créer le
Process()
méthode comme ceci:Enfin, dans le
OnStop()
rappel, déclencher le fil à l'arrêt:@Matt - merci pour le code, très utile.
J'ai trouvé cela a fonctionné encore mieux si j'ai ajouté un autre test sur _shutdownEvent: