Vamos supor que temos um daemon tão trivial escrito em python:
def mainloop():
while True:
# 1. do
# 2. some
# 3. important
# 4. job
# 5. sleep
mainloop()
e nós o daemonizamos usando o start-stop-daemon
qual, por padrão, envia sinal SIGTERM
( TERM
) --stop
.
Vamos supor que a etapa atual executada seja #2
. E neste exato momento estamos enviando TERM
sinal.
O que acontece é que a execução termina imediatamente.
Descobri que posso lidar com o evento de sinal usando, signal.signal(signal.SIGTERM, handler)
mas o fato é que ele ainda interrompe a execução atual e passa o controle para handler
.
Então, minha pergunta é - é possível não interromper a execução atual, mas manipular o TERM
sinal em um thread separado (?) Para que eu pudesse configurar shutdown_flag = True
para que mainloop()
tivesse a chance de parar normalmente?
python
daemon
sigterm
start-stop-daemon
zerkms
fonte
fonte
signalfd
e mascarando a entrega doSIGTERM
processo.Respostas:
Uma solução limpa de usar baseada em classe:
fonte
False
valor é definido apenas uma vez e, em seguida, só pode ir de Falso para Verdadeiro, para que o acesso múltiplo não seja um problema.Primeiro, não tenho certeza de que você precise de um segundo thread para definir o
shutdown_flag
.Por que não configurá-lo diretamente no manipulador SIGTERM?
Uma alternativa é gerar uma exceção do
SIGTERM
manipulador, que será propagado pela pilha. Supondo que você tenha um tratamento adequado de exceções (por exemplo, comwith
/contextmanager
etry: ... finally:
blocos), este deve ser um desligamento bastante simples, semelhante a se você estivesse no Ctrl+Cseu programa.Exemplo de programa
signals-test.py
:Agora veja o Ctrl+Ccomportamento:
Desta vez, eu o envio
SIGTERM
após 4 iterações comkill $(ps aux | grep signals-test | awk '/python/ {print $2}')
:Dessa vez, habilito meu
SIGTERM
manipulador personalizado e o envioSIGTERM
:fonte
Eu acho que você está perto de uma possível solução.
Executar
mainloop
em um segmento separado e estendê-lo com a propriedadeshutdown_flag
. O sinal pode ser capturadosignal.signal(signal.SIGTERM, handler)
na linha principal (não em uma linha separada). O manipulador de sinal deve ser definidoshutdown_flag
como True e aguardar que o encadeamento termine comthread.join()
fonte
Aqui está um exemplo simples, sem threads ou classes.
fonte
Com base nas respostas anteriores, criei um gerenciador de contexto que protege contra sigint e sigterm.
fonte
Encontrei a maneira mais fácil para mim. Aqui está um exemplo com garfo para maior clareza de que esse caminho é útil para o controle de fluxo.
fonte
A solução mais simples que encontrei, inspirada nas respostas acima, é
fonte