Cómo hacer retroceder el arranque, en lugar de rendirse

24

Quiero que Upstart haga dos cosas:

  1. deja de intentar reaparecer un proceso fallido tan rápido
  2. nunca te rindas tratando de reaparecer

En un mundo ideal, el advenedizo intentaría reiniciar un proceso muerto después de 1 segundo, luego duplicaría ese retraso en cada intento, hasta que llegara a una hora.

¿Es posible algo así?

fadedbee
fuente
never give up trying to respawnpermanece sin respuesta. ¿nadie?
vemv

Respuestas:

29

Upstart Cookbook recomienda un retraso posterior a la detención ( http://upstart.ubuntu.com/cookbook/#delay-respawn-of-a-job ). Usa la respawnestrofa sin argumentos y continuará intentándolo para siempre:

respawn
post-stop exec sleep 5

(Obtuve esto de esta pregunta de Ubuntu )

Para agregar la parte de retraso exponencial, intentaría trabajar con una variable de entorno en el script posterior a la parada, creo que algo así como:

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

** EDITAR **

Para aplicar el retraso solo al reaparecer, evitando el retraso en una parada real, use lo siguiente, que verifica si el objetivo actual es "parar" o no:

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
fuente
1
Si usa respawn sin argumentos, el valor predeterminado es volver a intentarlo hasta diez veces en una ventana de cinco minutos.
Jamie Cockburn
3
El problema con esto para un sistema de producción es que una vez que alcanza el máximo (60 s) siempre tomará 60 segundos, incluso si el sistema vuelve a estar en buen estado. Tal vez podría ser post-startrestablecerlo a 1.
José F. Romaniello
2
@JamieCockburn El intervalo predeterminado no es 5 minutos, son 5 segundos .
Zitrax
1
Esto casi funcionó para mí, pero el truco set-env golpeó "initctl: No está permitido modificar el entorno de trabajo PID 1". En cambio, tuve que recurrir a almacenar el valor de suspensión en / tmp / $ UPSTART_JOB y luego buscarlo de nuevo
Neil McGill
5

Como ya se mencionó, use respawnpara activar la reaparición.

Sin embargo, la cobertura de Upstart Cookbookrespawn-limit dice que deberá especificar respawn limit unlimitedpara tener un comportamiento de reintento continuo.

Por defecto, volverá a intentarlo siempre que el proceso no reaparezca más de 10 veces en 5 segundos.

Por lo tanto, sugeriría:

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

Terminé poniendo startun cronjob. Si el servicio se está ejecutando, no tiene ningún efecto. Si no se está ejecutando, inicia el servicio.

fadedbee
fuente
3
¡Tan janky y tan elegante! <3
pkoch
3

He mejorado la respuesta de Roger. Por lo general, desea retroceder cuando hay un problema en el software subyacente que hace que se bloquee mucho en un corto período de tiempo, pero una vez que el sistema se ha recuperado, desea restablecer el tiempo de retroceso. En la versión de Roger, el servicio siempre duerme durante 60 segundos, incluso para bloqueos individuales y aislados después de 7 bloqueos.

#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
fuente
1

Desea respawn limit <times> <period>, aunque esto no proporcionaría el comportamiento exponencial que está buscando, probablemente lo haría para la mayoría de los casos de uso. Puede intentar usar valores muy grandes para timesy periodaproximar lo que intenta lograr. Vea la sección de man 5 initrespawn limit para referencia.

el wabbit
fuente
66
El período es el período en el que se cuentan las reapariciones , no un retraso entre reapariciones.
fadedbee
1
Lo que supongo que significaría que incluso si usaras respawn limit 10 3600los 10 intentos, probablemente se usarían de inmediato, ya que de forma predeterminada no hay demora.
Zitrax
0

Otros han respondido a la pregunta para las estrofas de reaparición y límite de reaparición, pero me gustaría agregar mi propia solución para el script posterior a la detención que controla el retraso entre el reinicio.

El mayor problema con la solución propuesta por Roger Dueck es que el retraso hace que 'reiniciar jobName' se cuelgue hasta que se complete la suspensión.

Mi adición verifica si hay un reinicio en progreso antes de determinar si se debe dormir o no.

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
fuente