2009-05-15 6 views
1

J'ai un service Windows qui accède essentiellement à une boîte aux lettres et lit les courriels. J'essaie de trouver la meilleure façon de vérifier la boîte aux lettres toutes les x secondes.Quelle est la meilleure façon d'appeler/démarrer un service Windows toutes les x secondes?

Une méthode consiste à appeler simplement Thread.Sleep, puis à rappeler la méthode de démarrage, par ex.

protected override void OnStart(string[] args) 
{ 
    // get config settings 
    CheckMailbox(); 
} 

public void CheckMailbox() 
{ 
    int x = 5000; 

    // do stuff 

    Thread.Sleep(x); 
    CheckMailbox(); 
} 

Vous ne savez pas si c'est la meilleure façon de procéder? Pour approfondir ensuite cette question, je comprends que vous pouvez appeler un service Windows en exposant le service via WCF. Dans ce cas, si une application Web appelait le processus pour démarrer, il y aurait des threads en conflit? Comment pourrais-je faire face à cela? Devrais-je créer un nouveau thread à chaque fois et le mettre dans une file d'attente?

Répondre

7

Dormir est généralement une mauvaise idée. En dehors de toute autre chose, cela signifie que vous ne répondrez pas à l'événement Stop rapidement.

Vous devez utiliser un . Il y a deux qui sont appropriés pour les services:

Dans chaque cas, vous dites essentiellement ce que vous voulez arriver à chaque fois que la minuterie « tiques » et quand vous le souhaitez Feu.

Mon didacticiel de filetage a un section explaining some of the differences between available timers.

Je ne suis pas sûr de votre question WCF, mais je ne pense pas que votre service Web lancerait explicitement le service - il serait juste de le contacter via WCF. Oui, vous devrez potentiellement faire attention aux threads. Exactement ce dont vous devrez faire attention dépendra de ce que le service WCF expose.

+0

+1 - ah, bon point! Pendant le sommeil, le service ne réagira pas à l'arrêt des événements, c'est vrai. –

+0

Avec la minuterie Threading, disons que je vérifie la boîte aux lettres toutes les 10 secondes, et qu'il faut plus de 10 secondes pour ouvrir et traiter, cela aurait-il plusieurs threads fonctionnant à la fois correctement? – mickyjtwin

+0

+1 Les minuteurs sont utiles! @mickyjtwin: Si vous utilisez le System.Timers.Timer, il a des méthodes Start et Stop, vous pouvez donc appeler Stop, traiter vos mails, puis appeler Start. De cette façon, vous devrez attendre x secondes après avoir fini de traiter vos mails jusqu'à la prochaine vérification. Cependant, je ne pense pas que vous obtiendriez des fils parallèles dans le cas que vous suggérez; la Tick devrait être invoquée sur le thread où le timer a été créé, pas sur un nouveau thread. –

0

Si vous voulez l'exécuter en tant que service (en arrière-plan, sans que personne ne soit connecté), oui, c'est une façon de le faire.

Un autre serait d'avoir un minuteur qui appelle son gestionnaire d'événements "Tick" toutes les 5 secondes environ.

Si vos chèques ne sont pas aussi fréquents, vous pouvez également créer une application de console de ligne de commande et la programmer comme une «tâche planifiée» dans Windows.

Marc

0

Votre code a le problème d'ajouter à la pile d'appel pour chaque appel, puisque vous appelez la méthode à partir d'elle-même. À un certain point, vous obtiendrez une exception de dépassement de pile. Une attente est d'appeler une autre méthode sur un « thread en attente » qui marquera de retour après un certain temps:

private void CheckMailBox() 
{ 
    _waitHandle = new AutoResetEvent(true); 
    while (_waitHandle.WaitOne()) 
    { 
     // do the mail checking 
     ((IDisposable)_waitHandle).Dispose(); 
     _waitHandle = new AutoResetEvent(false); 
     ThreadPool.QueueUserWorkItem(WaitSomeTime, 2000); 
    } 

} 

private void WaitSomeTime(object state) 
{ 

    Thread.Sleep((int)state); 
    _waitHandle.Set(); 
} 
1

Code de base System.Threading.Timer:

// Class level variable in the Windows Service: 
private System.Threading.Timer timer; 

// This is in the constructor for a Windows Service. 
// interval would be the time in milliseconds in between ticks. 
// 0 is how long until it should start. 
timer = new Timer(new TimerCallback(TimerElapsed), null, 0, interval); 

// The TimerCallback in the Windows Service: 
private void TimerElapsed(object o) 
{ 
    // Do email stuff here. 
} 
0

Une amélioration possible au-delà en utilisant un timer serait d'utiliser un composant de planification dans votre service. Ensuite, vous pouvez configurer votre service pour qu'il soit l'hôte du code qui accèdera à votre boîte aux lettres.

Quartz.NET est un composant de programmation open source qui peut le faire. Il vous permet de configurer la programmation exactement comme vous le souhaitez et il est assez facile à utiliser.

0

Ok, alors que votre question de synchronisation est assez bien gérée (et je suis d'accord avec la plupart de ce qui précède), je peux offrir quelques informations concernant WCF. Un service WCF est simplement hébergé dans un domaine d'application. Ce domaine peut être un formulaire Windows, une application console, ASP.net et, dans ce cas, un service Windows.

Donc dans un sens, vous n'êtes pas exposer la via WCF, le service windows vous êtes plus qui héberge le service WCF dans un domaine d'application Windows Service. Je vous conseille de tester votre service (objets de minuterie inclus) dans un Windows formulaire avant de faire la transition vers le service Windows. Plus facile à déboguer et à tester.

Un service hébergé WCF est en fait en cours d'exécution dans son propre thread:

serviceType_MyEmailer = typeof(MyEmailerServiceType); 
    ServiceHost host_MyEmailer; 


    host_MyEmailer = new ServiceHost(serviceType_MyEmailer); 

Rechercher un exemple "DerivativesCalculatorService" en ligne. Vous montre comment héberger un service WCF dans le code.

L'astuce de synchronisation ici est dans votre propre service. Vous pourriez créer votre classe de service pour être une classe singleton qui est initialisée immédiatement, et lors de son initialisation, elle pourrait démarrer son objet Timer (comme vu avec les autres réponses). De cette façon, votre service WCF aurait une instance persistante de votre classe avec son objet Timer en cours de désactivation. Avoir tout cela hébergé dans un service Windows et vous avez terminé.

Espérons que cela aide.

Questions connexes