在 upstart 脚本中添加手动“等待”

在 upstart 脚本中添加手动“等待”

我有一个如下所示的新贵脚本:

start on stopped hw_boot
script
/usr/bin/python_program
end script

这很好。但为了优化,我想隐藏缓慢的 Python 库导入的延迟(目前需要 5-10 秒)。一个明显的方法是即使在硬件启动期间也启动 Python 库导入。

所以,我想要做的事情如下:

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

我们如何在 upstart 脚本中编写一个逻辑来等待“stopped hw_boot”?

答案1

我不会详细介绍并为您列出整个 Upstart 脚本,因为您似乎已经知道如何编写它们,但我将向您展示关键部分。

从你的问题中我将使用

  • some_boot_event作为“较早”的启动事件,应该触发初始化Python 程序和
  • stopped hw_boot因为这应该会触发执行Python 程序。

它的工作原理如下:

  1. 重构您的 Python 程序以包含一个可调用的入口点,该入口点稍后可从其他模块任意时间调用。(理想情况下,您的 Python 模块/程序已经以这种方式编写。)如果程序当前在模块加载时(即在全局范围内)执行任何非初始化任务,则应将它们包装在方法中。

    例如,如果你的模块当前看起来像这样,

    #!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()
    
  2. 编写一个 Python 模块,导入 Python 程序的主模块,等待信号,然后调用主模块的主要方法:

    #!/usr/bin/env python3
    import signal, MyMainModule
    # Perform other initialisation tasks if necessary
    signal.sigwaitinfo((signal.SIGCONT,))
    MyMainModule.main()
    

    如果你不能使用 Python 3,你可以参考Python 3 的 Signal.sigwaitinfo 相当于 Python 2.7 吗?在 Python 2 中可以找到等效的东西。

  3. 使用 处的先前 Python 程序启动 Upstart “服务” 任务some_boot_event。我们将其命名为my_service_task

  4. 启动第二个 Upstart “一次性” 任务,并向前一个任务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

相关内容