Eu não vou entrar em detalhes e alinhar todos os scripts do Upstart para você já que você já sabe como escrevê-los, mas vou mostrar as partes cruciais.
Da sua pergunta, vou usar
-
some_boot_event
como o evento de inicialização "anterior" que deve acionar a inicialização do programa Python e -
stopped hw_boot
como o par que deveria acionar a execução do programa em Python.
É assim que funciona:
-
Refatore seu programa em Python para incluir um ponto de entrada que pode ser chamado posteriormente em um momento arbitrário de outros módulos. (Idealmente, seu módulo / programa Python já está escrito dessa forma.) Se o programa atualmente executa qualquer tarefa que não seja de inicialização no tempo de carregamento do módulo, i. e. no escopo global, você deve envolvê-los dentro de um método.
g. se seu módulo atualmente se parece com isso,
#!shebang import foo, bar # ... various constant, class and method definitions ... print("Hello World")
você deve refatorar para isso:
#!shebang import foo, bar # ... various constant, class and method definitions ... def main(): print("Hello World!") if __name__ == "__main__": main()
-
Escreva um módulo Python que importe o módulo principal do seu programa Python, aguarde um sinal e invoque o método main do módulo principal:
#!/usr/bin/env python3 import signal, MyMainModule # Perform other initialisation tasks if necessary signal.sigwaitinfo((signal.SIGCONT,)) MyMainModule.main()
Se você não pode usar o Python 3, você pode consultar o equivalente Signal.sigwaitinfo do Python 3 no Python 2.7? para algo equivalente no Python 2.
-
Inicie uma tarefa de "serviço" do Upstart com o programa Python anterior em
some_boot_event
. Vamos chamá-lo demy_service_task
. -
Inicia uma segunda tarefa “one-shot” do Upstart em
stopped hw_boot
que envia um sinalCONT
para a tarefa anterior:set -e kill -s CONT -- "$(initctl status my_service_task | grep -oEe '[0-9]+$')"
Se você precisar relatar informações de status de my_service_task
para a tarefa na etapa 4, poderá configurar uma FIFO antes de enviar o sinal na última:
#!/usr/bin/env python3
import errno, signal, MyMainModule
# Perform other initialisation tasks if necessary
signal.sigwaitinfo((signal.SIGCONT,))
try:
return_value = MyMainModule.main()
except Exception as ex:
return_value = ex
try:
with open("/var/run/my_service_task.status") as status_fifo:
print(return_value, file=status_fifo)
except OSError as ex:
if ex.errno not in (errno.ENOENT, errno.EPIPE):
raise ex
if isinstance(return_value, Exception):
raise return_value
No final da leitura:
set -e
STATUS_FIFO=/var/run/my_service_task.status
mkfifo -m 0600 "$STATUS_FIFO"
trap 'rm -f "$STATUS_FIFO"' 0 INT QUIT TERM
kill -s CONT -- "$(initctl status my_service_task | grep -oEe '[0-9]+$')"
read return_value < "$STATUS_FIFO"
# Do stuff with $return_value