Eu gostaria de um daemonizador que pudesse transformar um script ou comando genérico arbitrário em um daemon .
Existem dois casos comuns com os quais eu gostaria de lidar:
Tenho um script que deve ser executado para sempre. Se ele morrer (ou na reinicialização), reinicie-o. Não deixe que haja duas cópias em execução ao mesmo tempo (detecte se uma cópia já está sendo executada e não a execute nesse caso).
Tenho um script simples ou comando de linha de comando que gostaria de executar repetidamente para sempre (com uma pequena pausa entre as execuções). Novamente, não permita que duas cópias do script sejam executadas ao mesmo tempo.
Claro que é trivial escrever um loop "while (true)" em torno do script no caso 2 e, em seguida, aplicar uma solução para o caso 1, mas uma solução mais geral resolverá apenas o caso 2 diretamente, uma vez que se aplica ao script no caso 1 como bem (você pode apenas querer um mais curto ou sem pausa se o script não se destina a morrer nunca (é claro que se o script realmente não nunca morrem, em seguida, a pausa na verdade não importa)).
Observe que a solução não deve envolver, digamos, a adição de código de bloqueio de arquivo ou gravação PID aos scripts existentes.
Mais especificamente, gostaria de um programa "daemonize" que posso executar como
% daemonize myscript arg1 arg2
ou, por exemplo,
% daemonize 'echo `date` >> /tmp/times.txt'
que manteria uma lista crescente de datas anexada a times.txt. (Observe que se o (s) argumento (s) para daemonize for um script que executa para sempre como no caso 1 acima, então daemonize ainda fará a coisa certa, reiniciando-o quando necessário.) Eu poderia então colocar um comando como o acima em meu .login e / ou cron-lo de hora em hora ou minuto (dependendo de quão preocupado eu estava sobre ele morrer inesperadamente).
NB: O script daemonize precisará lembrar a string de comando que está daemonizando para que, se a mesma string de comando for daemonizada novamente, não execute uma segunda cópia.
Além disso, a solução deve funcionar idealmente no OS X e no Linux, mas soluções para um ou outro são bem-vindas.
EDIT: Tudo bem se você tiver que invocá-lo com sudo daemonize myscript myargs
.
(Se estou pensando nisso tudo errado ou há soluções parciais rápidas e sujas, adoraria ouvir isso também.)
PS: Caso seja útil, aqui está uma pergunta semelhante específica para python.
E esta resposta a uma pergunta semelhante tem o que parece ser uma expressão útil para uma demonização rápida e suja de um script arbitrário:
Respostas:
Você pode daemonizar qualquer executável no Unix usando nohup e o operador &:
O comando nohup permite que você desligue sua sessão de shell sem matar seu script, enquanto o & coloca seu script em segundo plano para que você obtenha um prompt de shell para continuar sua sessão. O único problema menor com isso é a saída padrão e o erro padrão, ambos enviados para ./nohup.out, portanto, se você iniciar vários scripts nesta mansão, a saída deles será interligada. Um comando melhor seria:
Isso enviará o padrão para o arquivo de sua escolha e o erro padrão para um arquivo diferente de sua escolha. Se quiser usar apenas um arquivo para saída padrão e erro padrão, você pode usar o seguinte:
O 2> & 1 diz ao shell para redirecionar o erro padrão (descritor de arquivo 2) para o mesmo arquivo de saída padrão (descritor de arquivo 1).
Para executar um comando apenas uma vez e reiniciá-lo se ele morrer, você pode usar este script:
O primeiro argumento é o nome do arquivo pid a ser usado. O segundo argumento é o comando. E todos os outros argumentos são os argumentos do comando.
Se você nomear esse script de restart.sh, é assim que você o chamaria:
fonte
trap EXIT
)<
notest
é uma comparação ASCII e não uma comparação inteira. Ainda pode funcionar, mas pode levar a bugs.Peço desculpas pela longa resposta (por favor, veja os comentários sobre como minha resposta acerta as especificações). Estou tentando ser abrangente, para que você tenha uma boa vantagem. :-)
Se você é capaz de instalar programas (tem acesso root), e está disposto a fazer um trabalho braçal único para configurar seu script para a execução do daemon (ou seja, mais envolvido do que simplesmente especificar os argumentos da linha de comando para executar na linha de comando, mas só precisa ser feito uma vez por serviço), eu tenho uma maneira que é mais robusta.
Envolve o uso de daemontools . O restante da postagem descreve como configurar serviços usando daemontools.
Configuração inicial
/service
. O instalador já deve ter feito isso, mas é só verificar, ou se estiver instalando manualmente. Se você não gostar desse local, poderá alterá-lo em seusvscanboot
script, embora a maioria dos usuários de daemontools esteja acostumada a usar/service
e ficará confuso se você não usá-lo.init
(ou seja, não usa/etc/inittab
), você precisará usar o pré-instaladoinittab
como base para organizarsvscanboot
a chamada deinit
. Não é difícil, mas você precisa saber como configurar oinit
que seu SO usa.svscanboot
é um script que chamasvscan
, que faz o trabalho principal de procura de serviços; é chamado deinit
entãoinit
providenciará para reiniciá-lo se ele morrer por qualquer motivo.Configuração por serviço
/var/lib/svscan
, mas qualquer novo local vai servir.Eu costumo usar um script para configurar o diretório de serviço, para economizar muito trabalho manual repetitivo. por exemplo,
onde
some-service-name
é o nome que você deseja dar ao seu serviço,user
é o usuário para executar esse serviço eloguser
é o usuário para executar o logger. (O registro é explicado em breve.)fghack
, embora haja uma troca: você não pode mais controlar o programa usandosvc
.run
script para garantir que ele está fazendo o que você deseja. Pode ser necessário fazer umasleep
chamada na parte superior, se você espera que seu serviço saia com frequência./service
apontando para o diretório de serviço. (Não coloque diretórios de serviço diretamente dentro/service
; isso torna mais difícil remover o serviço dosvscan
watch.)Exploração madeireira
mkservice
);svscan
cuida do envio de mensagens de log para o serviço de registro.mkservice
criará arquivos de registro com registro de data e hora e rotação automática nolog/main
diretório. O arquivo de log atual é chamadocurrent
.tai64nlocal
traduzirá os carimbos de data / hora em um formato legível por humanos. (TAI64N é um carimbo de data / hora atômico de 64 bits com uma contagem de nanossegundos.)Serviços de controle
svstat
para obter o status de um serviço. Observe que o serviço de registro é independente e tem seu próprio status.svc
. Por exemplo, para reiniciar seu serviço, usesvc -t /service/some-service-name
;-t
significa "enviarSIGTERM
".-h
(SIGHUP
),-a
(SIGALRM
),-1
(SIGUSR1
),-2
(SIGUSR2
) e-k
(SIGKILL
).-d
. Você também pode impedir que um serviço seja iniciado automaticamente na inicialização, criando um arquivo nomeadodown
no diretório do serviço.-u
. Isso não é necessário, a menos que você o tenha baixado anteriormente (ou configurado para não iniciar automaticamente).-x
; geralmente usado com-d
para encerrar o serviço também. Esta é a maneira usual de permitir que um serviço seja removido, mas você tem que desvincular o serviço/service
primeiro, ou entãosvscan
reiniciará o supervisor. Além disso, se você criou seu serviço com um serviço de registro (mkservice -l
), lembre-se de também sair do supervisor de registro (por exemplo,svc -dx /var/lib/svscan/some-service-name/log
) antes de remover o diretório de serviço.Resumo
Prós:
init
fornecido.Contras:
svc
e não pode executar os scripts de execução diretamente (já que eles não estariam sob o controle do supervisor).supervise
processos em sua mesa processo.)Em suma, acho que o daemontools é um sistema excelente para as suas necessidades. Agradeço qualquer pergunta sobre como configurá-lo e mantê-lo.
fonte
supervise
, o supervisor, se encarrega de reiniciar qualquer serviço que saia. Espera um segundo entre os reinícios; se isso não for tempo suficiente para você, coloque em suspensão no início do script de execução de serviço.supervise
é apoiado por ele mesmosvscan
, portanto, se um supervisor morrer, ele será reiniciado. 2b.svscan
é apoiado porinit
, que será reiniciado automaticamentesvscan
conforme necessário. 2c. Se vocêinit
morrer por qualquer motivo, você está ferrado de qualquer maneira. :-Psvstat
esvc
podem trabalhar.Eu acho que você pode querer tentar
start-stop-daemon(8)
. Verifique os scripts em/etc/init.d
qualquer distribuição Linux para exemplos. Ele pode localizar processos iniciados por linha de comando chamada ou arquivo PID, portanto, atende a todos os seus requisitos, exceto ser um watchdog para seu script. Mas você sempre pode iniciar outro script de watchdog daemon que apenas reinicia seu script, se necessário.fonte
start-stop-daemon
(a partir de 10.9).start-stop-daemon
ainda está vivo e funcionando no Linux; mas depois de ler resposta stackoverflow.com/a/525406/45375 eu percebi que a OSX faz sua própria coisa:launchd
.Você deve dar uma olhada no daemonize . Permite detectar a segunda cópia (mas usa mecanismo de bloqueio de arquivo). Também funciona em diferentes distribuições UNIX e Linux.
Se você precisa iniciar automaticamente seu aplicativo como daemon, você precisa criar o script de inicialização apropriado.
Você pode usar o seguinte modelo:
fonte
killproc
na parte de parada: se você teve um processo que, digamos, foi executadojava
, okillproc
fará com que todos os outros processos Java sejam encerrados também.$corelimit >/dev/null 2>&1 ; $*
Portanto, duvido que vá daemonizar qualquer coisa ...Como alternativa ao já mencionado
daemonize
edaemontools
, existe o comando daemon do pacote libslack.daemon
é bastante configurável e se preocupa com todas as coisas tediosas daemon, como reinicialização automática, registro ou manipulação de pidfile.fonte
Se você estiver usando o OS X especificamente, sugiro que dê uma olhada em como funciona o launchd. Ele verificará automaticamente se o script está em execução e o reiniciará, se necessário. Também inclui todos os tipos de recursos de agendamento, etc. Deve atender aos requisitos 1 e 2.
Para garantir que apenas uma cópia do seu script possa ser executada, você precisa usar um arquivo PID. Geralmente, escrevo um arquivo em /var/run/.pid que contém um PID da instância em execução atual. se o arquivo existir quando o programa for executado, ele verifica se o PID no arquivo está realmente em execução (o programa pode ter travado ou esquecido de excluir o arquivo PID). Se for, aborte. Caso contrário, comece a executar e sobrescreva o arquivo PID.
fonte
Daemontools ( http://cr.yp.to/daemontools.html ) é um conjunto de utilitários bastante hard-core usados para fazer isso, escrito por dj bernstein. Eu usei isso com algum sucesso. A parte irritante disso é que nenhum dos scripts retorna qualquer resultado visível quando você os executa - apenas códigos de retorno invisíveis. Mas, uma vez em funcionamento, é à prova de balas.
fonte
Obtenha primeiro
createDaemon()
em http://code.activestate.com/recipes/278731/Então o código principal:
fonte
Esta é uma versão de trabalho completa com um exemplo que você pode copiar para um diretório vazio e experimentar (após instalar as dependências CPAN, que são Getopt :: Long , File :: Spec , File :: Pid e IPC :: System: : Simples - todos bastante padrão e altamente recomendados para qualquer hacker: você pode instalá-los todos de uma vez com
cpan <modulename> <modulename> ...
).keepAlive.pl:
exemplo.pl:
Agora você pode invocar o exemplo acima com:
./keepAlive.pl --pidfile=pidfile --command=./example.pl 1 2 3
e o arquivopidfile
será criado e você verá a saída:fonte
Você também pode experimentar o Monit . Monit é um serviço que monitora e relata outros serviços. Embora seja usado principalmente como uma forma de notificar (por e-mail e sms) sobre problemas de tempo de execução, ele também pode fazer o que a maioria das outras sugestões aqui defendem. Ele pode (re) iniciar e parar programas automaticamente, enviar e-mails, iniciar outros scripts e manter um registro de saída que você pode obter. Além disso, descobri que é fácil de instalar e manter, pois há uma documentação sólida.
fonte
Você poderia tentar o imortal. É um supervisor de plataforma cruzada * nix (agnóstico do sistema operacional).
Para uma experiência rápida no macOS:
Caso você esteja usando o FreeBSD a partir do ports ou usando o pkg:
Para Linux , baixando os binários pré-compilados ou da fonte: https://immortal.run/source/
Você pode usá-lo assim:
Ou por um arquivo YAML de configuração que oferece mais opções, por exemplo:
Se quiser manter também a saída de erro padrão em um arquivo separado, você pode usar algo como:
fonte
Eu fiz uma série de melhorias na outra resposta .
sleep
)-h
eval
, então você pode construir qualquer tipo de script de shell como uma string para enviar a este script como um último arg (ou args à direita) para que ele daemonize-lt
vez de<
Aqui está o script:
Uso:
Esteja ciente de que se você executar este script de diretórios diferentes, ele poderá usar arquivos pid diferentes e não detectar nenhuma instância em execução existente. Uma vez que foi projetado para executar e reiniciar comandos efêmeros fornecidos por meio de um argumento, não há como saber se algo já foi iniciado, porque quem pode dizer se é o mesmo comando ou não? Para melhorar a aplicação de executar apenas uma única instância de algo, é necessária uma solução específica para a situação.
Além disso, para que funcione como um daemon adequado, você deve usar (no mínimo) nohup como a outra resposta menciona. Não fiz nenhum esforço para fornecer resiliência aos sinais que o processo pode receber.
Mais um ponto a ser observado é que matar esse script (se ele foi chamado de outro script que foi morto, ou com um sinal) pode não conseguir matar a criança, especialmente se a criança for outro script. Não tenho certeza do porquê, mas parece ser algo relacionado ao modo de
eval
funcionamento, o que é misterioso para mim. Portanto, pode ser prudente substituir essa linha por algo que aceite apenas um único comando, como na outra resposta.fonte