Comment faire pour reculer, plutôt que d'abandonner

24

Je veux que Upstart fasse deux choses:

  1. arrêtez d'essayer de réapparaître si vite un processus qui a échoué
  2. n'abandonnez jamais d'essayer de réapparaître

Dans un monde idéal, un parvenu tenterait de redémarrer un processus mort après 1 seconde, puis doublerait ce délai à chaque tentative, jusqu'à ce qu'il atteigne une heure.

Est-ce que quelque chose comme ça est possible?

fadedbee
la source
never give up trying to respawnreste sans réponse. n'importe qui?
vemv

Réponses:

29

Le livre de recettes Upstart recommande un délai post-arrêt ( http://upstart.ubuntu.com/cookbook/#delay-respawn-of-a-job ). Utilisez la respawnstrophe sans arguments et elle continuera d'essayer indéfiniment:

respawn
post-stop exec sleep 5

(J'ai obtenu cela de cette question Ask Ubuntu )

Pour ajouter la partie retard exponentiel, j'essaierais de travailler avec une variable d'environnement dans le script post-stop, je pense que quelque chose comme:

env SLEEP_TIME=1
post-stop script
    sleep $SLEEP_TIME
    NEW_SLEEP_TIME=`expr 2 \* $SLEEP_TIME`
    if [ $NEW_SLEEP_TIME -ge 60 ]; then
        NEW_SLEEP_TIME=60
    fi
    initctl set-env SLEEP_TIME=$NEW_SLEEP_TIME
end script

** MODIFIER **

Pour appliquer le retard uniquement lors de la réapparition, en évitant le retard lors d'un arrêt réel, utilisez ce qui suit, qui vérifie si l'objectif actuel est "stop" ou non:

env SLEEP_TIME=1
post-stop script
    goal=`initctl status $UPSTART_JOB | awk '{print $2}' | cut -d '/' -f 1`
    if [ $goal != "stop" ]; then
        sleep $SLEEP_TIME
        NEW_SLEEP_TIME=`expr 2 \* $SLEEP_TIME`
        if [ $NEW_SLEEP_TIME -ge 60 ]; then
            NEW_SLEEP_TIME=60
        fi
        initctl set-env SLEEP_TIME=$NEW_SLEEP_TIME
    fi
end script
Roger Dueck
la source
1
Si vous utilisez respawn sans arguments, la valeur par défaut pour réessayer jusqu'à dix fois dans une fenêtre de cinq minutes.
Jamie Cockburn
3
Le problème avec cela pour un système de production est qu'une fois que vous atteignez le maximum (60s), cela prendra toujours 60secs même si le système est de retour en bonne santé. Peut-être qu'il pourrait y avoir post-startà le remettre à 1.
José F. Romaniello
2
@JamieCockburn L'intervalle par défaut n'est pas 5 minutes, c'est 5 secondes .
Zitrax
1
Cela a presque fonctionné pour moi - mais l'astuce set-env a frappé "initctl: Pas autorisé à modifier l'environnement de travail PID 1". Au lieu de cela, j'ai dû recourir à l'enregistrement de la valeur de sommeil dans / tmp / $ UPSTART_JOB, puis à la récupérer
Neil McGill
5

Comme déjà mentionné, utilisez respawnpour déclencher la réapparition.

Cependant, la couverture Upstart Cookbook surrespawn-limit indique que vous devrez spécifier respawn limit unlimitedd'avoir un comportement de relance continu.

Par défaut, il réessayera tant que le processus ne réapparaîtra pas plus de 10 fois en 5 secondes.

Je suggère donc:

respawn
respawn limit unlimited
post-stop <script to back-off or constant delay>
pingles
la source
4

J'ai fini par mettre startun cronjob. Si le service est en cours d'exécution, il n'a aucun effet. S'il ne fonctionne pas, il démarre le service.

fadedbee
la source
3
Si saccadé et si élégant! <3
pkoch
3

J'ai amélioré la réponse de Roger. En règle générale, vous souhaitez interrompre en cas de problème dans le logiciel sous-jacent, ce qui provoque un plantage important en peu de temps, mais une fois le système récupéré, vous souhaitez réinitialiser le délai d'interruption. Dans la version de Roger, le service dormira toujours pendant 60 secondes, même pour les plantages isolés et isolés après 7 plantages.

#The initial delay.
env INITIAL_SLEEP_TIME=1

#The current delay.
env CURRENT_SLEEP_TIME=1

#The maximum delay
env MAX_SLEEP_TIME=60

#The unix timestamp of the last crash.
env LAST_CRASH=0

#The number of seconds without any crash 
#to consider the service healthy and reset the backoff.
env HEALTHY_TRESHOLD=180

post-stop script
  exec >> /var/log/auth0.log 2>&1
  echo "`date`: stopped $UPSTART_JOB"
  goal=`initctl status $UPSTART_JOB | awk '{print $2}' | cut -d '/' -f 1`
  if [ $goal != "stop" ]; then
    CRASH_TIMESTAMP=$(date +%s)

    if [ $LAST_CRASH -ne 0 ]; then
      SECS_SINCE_LAST_CRASH=`expr $CRASH_TIMESTAMP - $LAST_CRASH`
      if [ $SECS_SINCE_LAST_CRASH -ge $HEALTHY_TRESHOLD ]; then
        echo "resetting backoff"
        CURRENT_SLEEP_TIME=$INITIAL_SLEEP_TIME
      fi
    fi

    echo "backoff for $CURRENT_SLEEP_TIME"
    sleep $CURRENT_SLEEP_TIME

    NEW_SLEEP_TIME=`expr 2 \* $CURRENT_SLEEP_TIME`
    if [ $NEW_SLEEP_TIME -ge $MAX_SLEEP_TIME ]; then
      NEW_SLEEP_TIME=$MAX_SLEEP_TIME
    fi

    initctl set-env CURRENT_SLEEP_TIME=$NEW_SLEEP_TIME
    initctl set-env LAST_CRASH=$CRASH_TIMESTAMP
  fi
end script
José F. Romaniello
la source
1

Vous voulez respawn limit <times> <period>- bien que cela ne fournisse pas le comportement exponentiel que vous recherchez, cela le ferait probablement pour la plupart des cas d'utilisation. Vous pouvez essayer d'utiliser des valeurs très grandes pour timeset periodpour approximer ce que vous essayez de réaliser. Voir la section de man 5 init sur respawn limitpour référence.

le-wabbit
la source
6
La période est la période pendant laquelle les réapparitions sont comptées , pas un délai entre les réapparitions.
fadedbee
1
Ce qui, je suppose, signifierait que même si vous utilisiez respawn limit 10 3600les 10 essais, ils seraient probablement épuisés immédiatement - car par défaut il n'y a pas de retard.
Zitrax
0

D'autres ont répondu à la question pour les strophes de réapparition et de limite de réapparition, mais je voudrais ajouter ma propre solution pour le script post-stop qui contrôle le délai entre les redémarrages.

Le plus gros problème avec la solution proposée par Roger Dueck est que le retard provoque le blocage du redémarrage de JobName jusqu'à ce que la mise en veille soit terminée.

Mon ajout vérifie s'il y a un redémarrage en cours avant de déterminer s'il faut ou non dormir.

respawn
respawn limit unlimited

post-stop script
    goal=`initctl status $UPSTART_JOB | awk '{print $2}' | cut -d '/' -f 1`
    if [[ $goal != "stop" ]]; then
            if ! ps aux | grep [r]estart | grep $UPSTART_JOB; then
                    sleep 60
            fi
    fi
end script
Whitham Reeve
la source