Comment puis-je déclencher un événement toutes les heures (ou un intervalle de temps spécifique chaque heure) dans .NET?

StackOverflow https://stackoverflow.com/questions/307798

  •  08-07-2019
  •  | 
  •  

Question

Je travaille sur un petit robot d'exploration Web qui s'exécutera dans la barre d'état système et analysera un site Web toutes les heures.

Quel est le meilleur moyen de faire en sorte que .NET lève un événement toutes les heures ou à un autre intervalle pour effectuer une tâche. Par exemple, je souhaite organiser un événement toutes les 20 minutes en fonction de l'heure. L'événement serait soulevé à:

00:20
00:40
01:00
01:20
01:40

et ainsi de suite. La meilleure façon de procéder est de créer une boucle sur un thread, qui vérifie en permanence si le temps est divisible par un intervalle donné et déclenche un événement de rappel si le temps est atteint. Je pense qu'il doit y avoir un meilleur moyen.

Je voudrais utiliser un Minuteur , mais je préférerais quelque chose qui suit un "calendrier". qui fonctionne à l'heure ou quelque chose du genre.

Est-ce possible de configurer mon application dans le planificateur de tâches Windows?

MISE À JOUR:
J'ajoute mon algorithme pour calculer l'intervalle de temps d'une minuterie. Cette méthode prend un " minute " paramètre, qui est quelle heure le minuteur doit déclencher une tique. Par exemple, si le " minute " Si le paramètre est égal à 20, la minuterie se mettra en marche aux intervalles de l’horaire ci-dessus.

int CalculateTimerInterval(int minute)
{
    if (minute <= 0)
        minute = 60;
    DateTime now = DateTime.Now;

    DateTime future = now.AddMinutes((minute - (now.Minute % minute))).AddSeconds(now.Second * -1).AddMilliseconds(now.Millisecond * -1);

    TimeSpan interval = future - now;

    return (int)interval.TotalMilliseconds;
}

Ce code est utilisé comme suit:

static System.Windows.Forms.Timer t;
const int CHECK_INTERVAL = 20;


static void Main()
{
    t = new System.Windows.Forms.Timer();
    t.Interval = CalculateTimerInterval(CHECK_INTERVAL);
    t.Tick += new EventHandler(t_Tick);
    t.Start();
}

static void t_Tick(object sender, EventArgs e)
{
    t.Interval = CalculateTimerInterval(CHECK_INTERVAL);
}
Était-ce utile?

La solution

System.Timers.Timer . Si vous souhaitez exécuter certaines heures de la journée, vous devez déterminer combien de temps il reste jusqu'à la prochaine fois et définir cet intervalle.

Ce n’est que l’idée de base. Selon votre degré de précision, vous pouvez en faire plus.

int minutes = DateTime.Now.Minute;
int adjust = 10 - (minutes % 10);
timer.Interval = adjust * 60 * 1000;  

Autres conseils

Vous pouvez trouver de l'aide auprès de Quartz.net http://quartznet.sourceforge.net/

Voici un exemple de système léger utilisant la synchronisation de threads et un appel asynchrone.

Je sais qu'il y a des inconvénients, mais j'aime bien utiliser ceci au lieu d'un minuteur lorsque vous démarrez un processus long (comme les services dorsaux planifiés). Comme il est intégré dans le thread du minuteur, vous n'avez pas à vous inquiéter de son expulsion avant la fin de l'appel initial. Cela pourrait être assez étendu pour lui faire utiliser un tableau de dates / heures comme temps de déclenchement ou lui ajouter des capacités supplémentaires. Je suis sûr que certains d'entre vous connaissent de meilleures méthodes.

    public Form1()
    {
        InitializeComponent();

        //some fake data, obviously you would have your own.
        DateTime someStart = DateTime.Now.AddMinutes(1);
        TimeSpan someInterval = TimeSpan.FromMinutes(2);

        //sample call
        StartTimer(someStart,someInterval,doSomething);
    }

    //just a fake function to call
    private bool doSomething()
    {
        DialogResult keepGoing = MessageBox.Show("Hey, I did something! Keep Going?","Something!",MessageBoxButtons.YesNo);
        return (keepGoing == DialogResult.Yes);
    }

    //The following is the actual guts.. and can be transplanted to an actual class.
    private delegate void voidFunc<P1,P2,P3>(P1 p1,P2 p2,P3 p3);
    public void StartTimer(DateTime startTime, TimeSpan interval, Func<bool> action)
    {
        voidFunc<DateTime,TimeSpan,Func<bool>> Timer = TimedThread;
        Timer.BeginInvoke(startTime,interval,action,null,null);
    }

    private void TimedThread(DateTime startTime, TimeSpan interval, Func<bool> action)
    {
        bool keepRunning = true;
        DateTime NextExecute = startTime;
        while(keepRunning)
        {
            if (DateTime.Now > NextExecute)
            {
                keepRunning = action.Invoke();
                NextExecute = NextExecute.Add(interval);
            }
            //could parameterize resolution.
            Thread.Sleep(1000);
        }            
    }

Une autre stratégie consiste à enregistrer la dernière fois que le processus a été exécuté et à déterminer si l’intervalle souhaité s’est écoulé depuis cette heure. Dans cette stratégie, vous souhaitez que votre événement soit déclenché si le temps écoulé est égal à OU SUPÉRIEUR à l'intervalle souhaité. De cette manière, vous pouvez gérer les situations dans lesquelles de longs intervalles (une fois par jour, par exemple) pourraient être manqués si l’ordinateur était en panne pour une raison quelconque.

Ainsi, par exemple:

  • lastRunDateTime = 5/2/2009 à 20h00
  • Je souhaite exécuter mon processus toutes les 24 heures
  • Lors d'un événement du minuteur, vérifiez si 24 heures OU PLUS se sont écoulées depuis la dernière exécution du processus.
  • Si oui, exécutez le processus, mettez à jour lastRunDateTime en y ajoutant l'intervalle souhaité (dans ce cas, 24 heures, mais peu importe ce que vous souhaitez)

Évidemment, pour que cette opération soit restaurée après la panne du système, vous devez stocker lastRunDateTime dans un fichier ou une base de données quelque part, afin que le programme puisse fonctionner là où il était laissé en reprise.

System.Windows.Forms.Timer (ou System.Timers.Timer)

mais depuis que vous dites que vous ne voulez pas utiliser les timers, vous pouvez exécuter un processus d’attente léger sur un autre thread (heure de contrôle, dormir quelques secondes, vérifier à nouveau, etc.) ou créer un composant événement (à l'aide d'un processus d'attente léger) à certaines heures ou intervalles programmés

Mon objectif est d'exécuter une importation vers 3 heures chaque nuit.

Voici mon approche, en utilisant System.Timers.Timer:

private Timer _timer;
private Int32 _hours = 0;
private Int32 _runAt = 3;

protected override void OnStart(string[] args)
{
    _hours = (24 - (DateTime.Now.Hour + 1)) + _runAt;
    _timer = new Timer();
    _timer.Interval = _hours * 60 * 60 * 1000;
    _timer.Elapsed += new ElapsedEventHandler(Tick);
    _timer.Start();
}

void Tick(object sender, ElapsedEventArgs e)
{
    if (_hours != 24)
    {
        _hours = 24;
        _timer.Interval = _hours * 60 * 60 * 1000;
    }

    RunImport();
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top