Como fazer o recuo inicial, em vez de desistir

24

Quero que o Upstart faça duas coisas:

  1. pare de tentar reaparecer um processo com falha tão rápido
  2. nunca desista de tentar reaparecer

Em um mundo ideal, o iniciante tentaria reiniciar um processo morto após 1s e depois duplicaria esse atraso em cada tentativa, até atingir uma hora.

É algo assim possível?

fadedbee
fonte
never give up trying to respawnpermanece sem resposta. alguém?
vemv

Respostas:

29

O Upstart Cookbook recomenda um atraso pós-parada ( http://upstart.ubuntu.com/cookbook/#delay-respawn-of-a-job ). Use a respawnestrofe sem argumentos e ela continuará tentando para sempre:

respawn
post-stop exec sleep 5

(Eu peguei isso nesta pergunta do Ubuntu )

Para adicionar a parte do atraso exponencial, eu tentaria trabalhar com uma variável de ambiente no script pós-parada, acho algo 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

** EDIT **

Para aplicar o atraso apenas ao reaparecer, evitando o atraso em uma parada real, use o seguinte, que verifica se o objetivo atual é "parar" ou não:

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
fonte
1
Se você usar o reaparecimento sem argumentos, o padrão é repetir até dez vezes em uma janela de cinco minutos.
Jamie Cockburn
3
O problema disso para um sistema de produção é que, quando você atingir o máximo (60s), ele sempre levará 60s, mesmo que o sistema volte ao normal. Talvez poderia haver post-startpara redefini-la para 1.
José F. Romaniello
2
@JamieCockburn O intervalo padrão não é de 5 minutos, é de 5 segundos .
Zitrax
1
Isso quase funcionou para mim - mas o truque set-env atingiu "initctl: Não é permitido modificar o ambiente de trabalho do PID 1". Em vez disso eu tive que recorrer a armazenar o valor de sono em / tmp / $ UPSTART_JOB e depois terceirização-lo de volta
Neil McGill
5

Como já mencionado, use respawnpara acionar o reaparecimento.

No entanto, a coberturarespawn-limit do Upstart Cookbook diz que você precisará especificar respawn limit unlimitedpara ter um comportamento de repetição contínua.

Por padrão, ele tentará novamente enquanto o processo não reaparecer mais de 10 vezes em 5 segundos.

Eu sugeriria, portanto:

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

Acabei colocando um startem um cronjob. Se o serviço estiver em execução, não terá efeito. Se não estiver em execução, inicia o serviço.

fadedbee
fonte
3
Tão excêntrico e tão elegante! <3
pkoch 26/04/16
3

Fiz uma melhoria na resposta de Roger. Normalmente, você deseja se retirar quando houver um problema no software subjacente, causando uma falha muito em um curto período de tempo, mas depois que o sistema se recuperar, você deseja redefinir o tempo de retirada. Na versão de Roger, o serviço dorme por 60 segundos sempre, mesmo para falhas isoladas e isoladas após 7 falhas.

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

Você deseja respawn limit <times> <period>- embora isso não forneça o comportamento exponencial que você está procurando, provavelmente o faria na maioria dos casos de uso. Você pode tentar usar valores muito grandes para timese periodaproximar o que você tenta alcançar. Veja a seção do man 5 initrespawn limit para referência.

o wabbit
fonte
6
O período é o período em que os respawns são contados , e não um atraso entre os respawns.
fadedbee
1
O que eu suponho que significaria que, mesmo que você usasse respawn limit 10 3600as 10 tentativas, provavelmente seria esgotado imediatamente - já que, por padrão, não há atraso.
Zitrax
0

Outros responderam à pergunta para estrofes de respawn e limite de respawn, mas eu gostaria de adicionar minha própria solução para o script pós-parada que controla o atraso entre reiniciar.

O maior problema com a solução proposta por Roger Dueck é que o atraso faz com que o 'restart jobName' seja interrompido até que o sono seja concluído.

Minha adição verifica se há uma reinicialização em andamento antes de determinar se deve ou não 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
fonte