Comment puis-je commencer un cronjob 1 heure plus tard chaque jour?

16

J'ai besoin de commencer un cronjob tous les jours, mais une heure plus tard chaque jour. Ce que j'ai jusqu'à présent fonctionne pour la plupart, sauf pour 1 jour de l'année:

0 0 * * * sleep $((3600 * (10#$(date +\%j) \% 24))) && /usr/local/bin/myprog

Lorsque le jour de l'année est 365, le travail commencera à 5h00, mais le lendemain (sans compter une année bissextile) aura un jour de l'année égal à 1, donc le travail commencera à 1h00. Comment puis-je me débarrasser de cette valise d'angle?

bouleau
la source
1
Une raison de ne pas le démarrer toutes les 25 heures?
HalosGhost
7
Et comment feriez-vous exactement cela? * / 25 en position heure ne le résoudra pas.
bouleau
@HalosGhost Merci pour votre suggestion! J'ai écrit une implémentation simple basée sur at.
Giulio Muscarello

Réponses:

23

Ma solution préférée serait de démarrer le travail toutes les heures, mais de faire vérifier le script lui-même s'il est temps de l'exécuter et de le quitter sans rien faire 24 fois sur 25.

crontab:

0 * * * *    /usr/local/bin/myprog

en haut de myprog:

[ 0 -eq $(( $(date +%s) / 3600 % 25 )) ] || exit 0

Si vous ne voulez pas apporter de modifications au script lui-même, vous pouvez également mettre la vérification "time to run" dans l'entrée crontab mais cela crée une longue ligne inesthétique:

0 * * * *    [ 0 -eq $(( $(date +\%s) / 3600 \% 25 )) ] && /usr/local/bin/myprog
Celada
la source
1
Les% doivent être échappés avec une barre oblique inverse dans la crontab.
bouleau
@birch Je n'ai jamais su ça! Je suppose que je n'avais jamais essayé auparavant d'inclure un% dans une crontab. Merci pour la correction, j'ai édité la réponse.
Celada
1
Cela me semble bien. Je n'ai aucune idée de ce que le PO veut faire en ce qui concerne l'heure d'été (printemps à venir, retard), mais le PO devrait faire des ajustements en conséquence.
emory
Je serais légèrement inquiet d'arrondir dans la division. Si, pour une raison quelconque, l'heure de dateretour du noyau était 1msantérieure à l'heure à laquelle vous vous attendiez à ce que le script s'exécute, la vérification donnerait un résultat incorrect.
kasperd
1
@kasperd Je ne sais pas, je suppose que vous avez peut-être raison de dire que différents processeurs signalent des heures différentes. Quant à ntpd, il s'efforce de ne faire que tourner l'horloge, pas de la sauter, spécifiquement pour éviter ce genre de problème, mais vous avez raison, il (ou ntpdate) peut parfois sauter le temps en arrière. Quant à cronmal calculer son retard de sommeil, je suis presque sûr que ce serait considéré comme un bug! Pourtant, le point est pris, et une solution de contournement serait de planifier le travail 30 minutes après l'heure, ce qui est moins susceptible de causer le problème ... Ou ajouter ± 1800 dans l'expression arithmétique avant de prendre le mod 3600 de reamainder.
Celada
7

Si votre système a systemd, vous pouvez utiliser des événements de temporisation pour cela. Définissez simplement un nouveau service , qui devrait contenir la commande / tâche que vous souhaitez exécuter, puis créez un événement de minuterie avec l' OnUnitActiveSecoption:

[Unit]
Description=daily + 1 hour task

[Timer]
OnUnitActiveSec=25h # run 25 hours after service was last started
AccuracySec=10min

[Install]
WantedBy=timers.target

Utilisez le même nom pour les fichiers, sauf qu'au lieu d' .serviceutiliser .timer.

Synthétiser:

  1. Créez un fichier appelé job.servicedans le /etc/systemd/system/répertoire.
  2. Remplissez-le avec les informations nécessaires. Vous pouvez vérifier la configuration à l'aide de systemctl status job.service.
  3. Créez un fichier appelé job.timerdans /etc/systemd/system/.
  4. Remplissez-le avec les informations requises:

    [Unit]
    Description=daily + 1 hour task
    
    [Timer]
    OnUnitActiveSec=25h # run 25 hours after service was last started
    AccuracySec=10min
    
    [Install]
    WantedBy=timers.target
    
  5. Vérifiez la minuterie à l'aide systemctl list-timers
  6. Terminé.
Braiam
la source
Si je devais m'éloigner de la simplicité de cron, j'utiliserais launchd, qui nécessiterait moins de travail que votre exemple pour systemd.
bouleau
6

Si cela ne vous dérange pas d'utiliser autre chose que cronjobs, je suggérerais l'utilitaire moins connu at. Écrivez simplement un script wrapper qui se planifie pour s'exécuter en 25 heures, puis appelle votre programme. Cela semble être la solution la plus propre.
Par exemple, vous pouvez écrire ceci dans ~ / script.sh:

echo "bash ~/script.sh" | at now + 25 hours
/usr/bin/yourprogram

Et puis exécutez simplement bash ~/script.shune fois.

Merci à @HalosGhost pour l'idée de planifier le travail une fois en 25 heures.

Giulio Muscarello
la source
2
Il y a 2 problèmes avec l'utilisation atà cette fin: (1) si le travail ne s'exécute pas correctement une seule fois, il échoue également probablement à se replanifier et ensuite non seulement la prochaine exécution, mais toutes les futures exécutions sont effectivement annulées jusqu'à ce qu'un humain le remarque, et (2) étant donné que le travail prend un certain temps non nul pour s'exécuter, en utilisant le now + 25 hoursmoyen naïf , il s'exécutera quelques secondes (ou plus) plus tard à chaque fois, et si ce décalage s'accumule au fil du temps, le rendant éventuellement exécuté complètement à tort temps.
Celada
2
Vous avez raison sur # 1; Je ne suis pas si sûr de # 2. Bien que je ne dispose pas de données, je ne pense pas que le délai entre le changement d'horloge et le travail en cours soit déclenché puis reprogrammé soit suffisamment important pour être perceptible - d'autant plus que la résolution de atest limitée à quelques minutes et démarre tous les travaux à [heure]: 00.
Giulio Muscarello
1
@Celada: Planifier le prochain attravail première chose que dans le scénario à éviter ces problèmes. Néanmoins, si une erreur se produit, toute la chaîne est rompue, ce qui peut ou non être souhaité: si le cas d'utilisation est "ne l'exécuter que lorsqu'il fonctionne", le non-redémarrage est une fonctionnalité intéressante. Mais si le cas d'utilisation est "toujours exécuté, même si le dernier a échoué", ce atn'est pas le bon outil.
évêque du