У меня есть сценарий выскочки, как показано ниже:
start on stopped hw_boot
script
/usr/bin/python_program
end script
Это отлично работает. Но для оптимизации я хотел бы скрыть задержку медленного импорта библиотеки python (в настоящее время она занимает 5-10 секунд). Один из очевидных способов - запустить импорт библиотеки python даже во время загрузки hw.
Итак, я хочу сделать следующее:
start on some_boot_event (this event is earlier than stopped hw_boot)
script
//import bunch of python libraries that are needed later
wait for "stopped hw_boot"
/usr/bin/python_program
end_script
Как мы можем написать логику ждать «остановленного hw_boot» в сценарии выскочки?
Я не буду вдаваться в подробности и вычеркивать все сценарии Upstart для вас, поскольку вы, похоже, знаете, как их писать, но я покажу вам важные части.
Из вашего вопроса Я буду использовать
some_boot_event в качестве «более раннего» загрузочного события, которое должно инициировать инициализацию программы Python и stopped hw_boot как равномерное, которое должно запускать выполнение программы Python.Вот как это работает:
Реорганируйте вашу программу Python, чтобы включить вызываемую точку входа, которую можно вызвать позже в произвольное время из других модулей. (В идеале ваш модуль / программа Python уже написан таким образом.) Если программа в настоящее время выполняет любую задачу без инициализации во время загрузки модуля, i. е. в глобальном масштабе, вы должны обернуть их внутри метода. E. g. если ваш модуль в настоящий момент выглядит так,#!shebang
import foo, bar
# ... various constant, class and method definitions ...
print("Hello World")
, вы должны его реорганизовать: #!shebang
import foo, bar
# ... various constant, class and method definitions ...
def main():
print("Hello World!")
if __name__ == "__main__":
main()
Записать модуль Python, который импортирует основной модуль вашей программы Python, ждет сигнала и затем вызывает основной метод основного модуля: #!/usr/bin/env python3
import signal, MyMainModule
# Perform other initialisation tasks if necessary
signal.sigwaitinfo((signal.SIGCONT,))
MyMainModule.main()
Если вы не можете использовать Python 3, вы можете обратиться к эквиваленту Signal.sigwaitinfo Python 3 в Python 2.7? для чего-то эквивалентного в Python 2. Запустите задачу «Службы» Upstart с предыдущей программой Python в some_boot_event. Назовем это my_service_task. Начните вторую задачу «одноразовое» на старте в stopped hw_boot, которая отправляет сигнал CONT в предыдущую задачу: set -e
kill -s CONT -- "$(initctl status my_service_task | grep -oEe '[0-9]+$')"
Если вам нужно сообщить информацию о статусе из my_service_task в задачу на шаге 4 вы можете настроить FIFO перед отправкой сигнала в последнем:
#!/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
На конце считывания:
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
Я не буду вдаваться в подробности и вычеркивать все сценарии Upstart для вас, поскольку вы, похоже, знаете, как их писать, но я покажу вам важные части.
Из вашего вопроса Я буду использовать
some_boot_event в качестве «более раннего» загрузочного события, которое должно инициировать инициализацию программы Python и stopped hw_boot как равномерное, которое должно запускать выполнение программы Python.Вот как это работает:
Реорганируйте вашу программу Python, чтобы включить вызываемую точку входа, которую можно вызвать позже в произвольное время из других модулей. (В идеале ваш модуль / программа Python уже написан таким образом.) Если программа в настоящее время выполняет любую задачу без инициализации во время загрузки модуля, i. е. в глобальном масштабе, вы должны обернуть их внутри метода. E. g. если ваш модуль в настоящий момент выглядит так,#!shebang
import foo, bar
# ... various constant, class and method definitions ...
print("Hello World")
, вы должны его реорганизовать: #!shebang
import foo, bar
# ... various constant, class and method definitions ...
def main():
print("Hello World!")
if __name__ == "__main__":
main()
Записать модуль Python, который импортирует основной модуль вашей программы Python, ждет сигнала и затем вызывает основной метод основного модуля: #!/usr/bin/env python3
import signal, MyMainModule
# Perform other initialisation tasks if necessary
signal.sigwaitinfo((signal.SIGCONT,))
MyMainModule.main()
Если вы не можете использовать Python 3, вы можете обратиться к эквиваленту Signal.sigwaitinfo Python 3 в Python 2.7? для чего-то эквивалентного в Python 2. Запустите задачу «Службы» Upstart с предыдущей программой Python в some_boot_event. Назовем это my_service_task. Начните вторую задачу «одноразовое» на старте в stopped hw_boot, которая отправляет сигнал CONT в предыдущую задачу: set -e
kill -s CONT -- "$(initctl status my_service_task | grep -oEe '[0-9]+$')"
Если вам нужно сообщить информацию о статусе из my_service_task в задачу на шаге 4 вы можете настроить FIFO перед отправкой сигнала в последнем:
#!/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
На конце считывания:
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