web-dev-qa-db-fra.com

Comment planifier un service Windows C # pour effectuer une tâche quotidiennement?

J'ai un service écrit en C # (.NET 1.1) et je veux qu'il effectue des opérations de nettoyage à minuit tous les soirs. Je dois garder tout le code contenu dans le service, alors quel est le moyen le plus simple d'y parvenir? Utilisation de Thread.Sleep() et vérification du temps écoulé?

79
ctrlalt3nd

Je n'utiliserais pas Thread.Sleep (). Utilisez une tâche planifiée (comme d'autres l'ont mentionné) ou configurez une minuterie dans votre service, qui se déclenche périodiquement (toutes les 10 minutes par exemple) et vérifiez si la date a changé depuis la dernière exécution:

private Timer _timer;
private DateTime _lastRun = DateTime.Now.AddDays(-1);

protected override void OnStart(string[] args)
{
    _timer = new Timer(10 * 60 * 1000); // every 10 minutes
    _timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
    _timer.Start();
    //...
}


private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
    // ignore the time, just compare the date
    if (_lastRun.Date < DateTime.Now.Date)
    {
        // stop the timer while we are running the cleanup task
        _timer.Stop();
        //
        // do cleanup stuff
        //
        _lastRun = DateTime.Now;
        _timer.Start();
    }
}
85
M4N

Découvrez Quartz.NET . Vous pouvez l'utiliser dans un service Windows. Il vous permet d'exécuter un travail selon un calendrier configuré et prend même en charge une syntaxe simple "travail cron". J'ai eu beaucoup de succès avec ça.

Voici un exemple rapide de son utilisation:

// Instantiate the Quartz.NET scheduler
var schedulerFactory = new StdSchedulerFactory();
var scheduler = schedulerFactory.GetScheduler();

// Instantiate the JobDetail object passing in the type of your
// custom job class. Your class merely needs to implement a simple
// interface with a single method called "Execute".
var job = new JobDetail("job1", "group1", typeof(MyJobClass));

// Instantiate a trigger using the basic cron syntax.
// This tells it to run at 1AM every Monday - Friday.
var trigger = new CronTrigger(
    "trigger1", "group1", "job1", "group1", "0 0 1 ? * MON-FRI");

// Add the job to the scheduler
scheduler.AddJob(job, true);
scheduler.ScheduleJob(trigger);
69
jeremcc

Une tâche quotidienne? Cela ressemble à une tâche planifiée (panneau de configuration) - aucun service n'est nécessaire ici.

20
Marc Gravell

Faut-il que ce soit un service réel? Pouvez-vous simplement utiliser les tâches planifiées intégrées dans le panneau de configuration de Windows.

15
Ian Jacobs

La façon dont j'accomplis ceci est avec une minuterie.

Exécutez une minuterie de serveur, faites-la vérifier l'heure/minute toutes les 60 secondes.

Si l'heure/la minute est correcte, exécutez votre processus.

Je l'ai en fait abstraite dans une classe de base que j'appelle OnceADayRunner.

Laissez-moi nettoyer un peu le code et je le posterai ici.

    private void OnceADayRunnerTimer_Elapsed(object sender, ElapsedEventArgs e)
    {
        using (NDC.Push(GetType().Name))
        {
            try
            {
                log.DebugFormat("Checking if it's time to process at: {0}", e.SignalTime);
                log.DebugFormat("IsTestMode: {0}", IsTestMode);

                if ((e.SignalTime.Minute == MinuteToCheck && e.SignalTime.Hour == HourToCheck) || IsTestMode)
                {
                    log.InfoFormat("Processing at: Hour = {0} - Minute = {1}", e.SignalTime.Hour, e.SignalTime.Minute);
                    OnceADayTimer.Enabled = false;
                    OnceADayMethod();
                    OnceADayTimer.Enabled = true;

                    IsTestMode = false;
                }
                else
                {
                    log.DebugFormat("Not correct time at: Hour = {0} - Minute = {1}", e.SignalTime.Hour, e.SignalTime.Minute);
                }
            }
            catch (Exception ex)
            {
                OnceADayTimer.Enabled = true;
                log.Error(ex.ToString());
            }

            OnceADayTimer.Start();
        }
    }

Le boeuf de la méthode est dans la vérification e.SignalTime.Minute/Hour.

Il y a des crochets pour les tests, etc., mais voici à quoi pourrait ressembler votre chronomètre écoulé.

3
CubanX

Comme d'autres l'ont déjà écrit, une minuterie est la meilleure option dans le scénario que vous avez décrit.

Selon vos besoins, il peut ne pas être nécessaire de vérifier l’heure actuelle toutes les minutes. Si vous n'avez pas besoin d'effectuer l'action exactement à minuit, mais juste dans l'heure qui suit, vous pouvez opter pour l'approche de Martin ou vérifier uniquement si la date a changé.

Si vous voulez exécuter votre action à minuit parce que vous vous attendez à une charge de travail réduite sur votre ordinateur, vous ferez mieux de prendre garde: la même hypothèse est souvent faite par d'autres et, tout à coup, vous avez 100 actions de nettoyage qui démarrent entre 0:00 et 0. : 01 heures.

Dans ce cas, vous devriez envisager de commencer votre nettoyage à un moment différent. Je fais habituellement ces choses non pas à l'heure, mais à une demi-heure (ma préférence personnelle étant de 1h30)

2
Treb

Je suggérerais que vous utilisiez une minuterie, mais que vous la configuriez pour vérifier toutes les 45 secondes, pas toutes les minutes. Sinon, vous pouvez vous retrouver dans des situations où, avec une charge importante, la vérification d'une minute particulière est manquée, car entre le moment où le chronomètre se déclenche et l'heure de votre code et la vérification de l'heure actuelle, vous avez peut-être manqué la minute cible.

1
GWLlosa

Vous pouvez également essayer la TaskSchedulerLibrary ici http://visualstudiogallery.msdn.Microsoft.com/a4a4f042-ffd3-42f2-a689-290ec13011f8

Implémentez la classe abstraite AbstractScheduledTask et appelez la méthode statique ScheduleUtilityFactory.AddScheduleTaskToBatch

0
Samuel

Pour ceux qui ont trouvé que les solutions ci-dessus ne fonctionnaient pas, c'est parce que vous pouvez avoir une this dans votre classe, ce qui implique une méthode d'extension qui, comme le dit le message d'erreur, n'a de sens que sur une classe statique non générique. Votre classe n'est pas statique. Cela ne semble pas être quelque chose de logique en tant que méthode d'extension, car il agit sur l'instance en question, alors supprimez la this.

0
Fandango68