Como reiniciar automaticamente um processo em segundo plano do linux se ele falhar?


32

Eu tenho um processo que é executado pelo script init.d em segundo plano. Por exemplo:

case "$1" in 
    start)
       /bin/myprocess &
    stop)
       killall myprocess
    restart)
       killall myprocess
       /bin/myprocess &
esac

Em certas condições, meu processo pode falhar e retornar. Existe alguma maneira (padrão) de como detectar sua falha e reiniciar automaticamente?


Claro, mas isso varia de acordo com a distribuição. Praticamente todos eles fornecem algum tipo de gerenciador de serviços.
21712 David Schwartz

Não há distribuição padrão, mas buildroot. Então eu tenho que fazê-lo manualmente ...
Honza

Respostas:


14

A maneira mais fácil seria adicioná-lo ao / etc / inittab , que é projetado para fazer esse tipo de coisa:

respawn Se o processo não existir, inicie o processo. Não espere sua finalização (continue verificando o arquivo / etc / inittab). Reinicie o processo quando ele morrer. Se o processo existir, não faça nada e continue varrendo o arquivo / etc / inittab.

Por exemplo, você pode fazer isso:

# Run my stuff
myprocess:2345:respawn:/bin/myprocess

Observe que /etc/inittabfunciona (ou até existe) se e somente se você tiver um sistema init baseado em sysvinit. Com o iniciante e com o systemd, não. É necessário instalar o busybox (shell muito primitivo, tornando o sysadm recuperar tarefas dolorosas, mas ele pode substituir um initd compatível com sysvinit) ou sysvinit (é um fóssil). Em um contêiner de docker, apenas o primeiro não é doloroso.
peterh diz restabelecer Monica

27

O Buildroot possui três sistemas init possíveis, portanto, existem três maneiras de fazer isso:

BusyBox init

Com isso, adicionamos uma entrada para /etc/inittab.

::respawn:/bin/myprocess

Observe que o BusyBox initpossui um /etc/inittabformato idiossincrático . O segundo campo não tem sentido e o primeiro campo não é um ID, mas um nome de base do dispositivo.

Linux "Sistema V" init

Novamente, adicionamos uma entrada para /etc/inittab.

myprocess:2345:respawn:/bin/myprocess

systemd

Um escreve um arquivo de unidade em, digamos /etc/systemd/system/myprocess.service:

[Unit]
Description=My Process

[Service]
ExecStart=/bin/myprocess
Restart=always

[Install]
WantedBy=multi-user.target

Habilite isso para iniciar automaticamente na inicialização com:

systemctl enable myprocess.service

Inicie-o manualmente com:

systemctl start myprocess.service

Leitura adicional


mas quando você usa essa abordagem noittab, seu processo não é mais acessível via interface de 'serviço', certo? ou seja, você não pode ir service mything startou service mything stopmais .... existe uma maneira de obter o melhor dos dois? ou seja, serviço sysvinit intransponível, mas também utilizá-lo via 'service'?
horseyguy 26/04

25

Que tal criar um subshell com um loop que chama constantemente o mesmo processo?

Se terminar, a próxima iteração do loop continua e o inicia novamente.

(while true; do 
    /bin/myprocess
done) &

Se o subshell morre, acabou. A única possibilidade nesse caso seria criar outro processo (eu o chamarei de necromante) que verifica se seu processo está ativo, inicie-o se não estiver e execute esse necromante com cron, para que você possa verificar regularmente.

O próximo passo seria saber o que poderia acontecer se o cron morrer, mas em algum momento você deve se sentir seguro e parar de se preocupar.


3

Você poderia fazer uso do Monit . É realmente fácil de usar e bastante flexível. Veja, por exemplo, esta configuração para reiniciar o processo do Tomcat em falha.

check process tomcat with pidfile /var/run/tomcat.pid
   start program = "/etc/init.d/tomcat start"
   stop  program = "/etc/init.d/tomcat stop"
   if failed port 8080 type tcp then restart

Ele também possui muitos exemplos de configuração para muitos casos de uso.


1

Se você não é um superusuário ou raiz e se o seu sistema Linux possui o Docker instalado, é possível criar uma imagem do docker do seu processo, usando o docker para reiniciar o processo se o sistema for reiniciado.

Arquivo: docker-compose.yml

version: "3"
services:
  lserver:
    image: your_docker_image:latest
    ports:
    - 8080:8080   # just use 8080 as an example
    restart: always  # this is where your process can be guaranteed to restart

Para iniciar o contêiner do docker,

docker-compose up -d

Eu acho que é fácil lidar com meu próprio processo com reinicialização automática se eu não sou um super usuário do sistema.

Para um exemplo de exemplo de como criar uma imagem de janela de encaixe, veja um exemplo rápido:

Arquivo: Dockerfile

FROM alpine:3.5

RUN apk update && apk upgrade && rm -rf /var/cache/apk/*
WORKDIR /app
COPY my-process-server /app
RUN ln -s /app/my-process-server /usr/local/bin/my-process-server

EXPOSE 8080

CMD ["my-process-server"]

0

No meu caso, como uma solução rápida, modifiquei e usei a solução do @Trylks para quebrar o programa que estava lançando. Queria que terminasse apenas na saída limpa.

Deve ser executado na maioria das conchas:

#!/bin/sh

echo ""
echo "Use: $0 ./program"
echo ""

#eg="/usr/bin/apt update"

echo "Executing $1 ..."

EXIT_CODE=1
(while [ $EXIT_CODE -gt 0 ]; do
    $1
    # loops on error code: greater-than 0
    EXIT_CODE=$?
done) &

0

Você pode usar restarter

start)
   restarter -c /bin/myprocess &
stop)
   pkill -f myprocess

Em sistemas mais recentes, use systemd que resolve todos esses problemas triviais

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.