将Python脚本作为Linux服务/守护进程

72 投票
2 回答
75398 浏览
提问于 2025-04-16 10:03

你好,

我正在尝试让一个Python脚本在(Ubuntu)Linux上作为服务(守护进程)运行。

网上有几种解决方案,比如:

http://pypi.python.org/pypi/python-daemon/

创建一个表现良好的Unix守护进程是比较复杂的,但每个守护进程程序所需的步骤大致相同。DaemonContext实例用于保存程序的行为和配置的进程环境;你可以把这个实例当作上下文管理器来进入守护进程状态。

http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/

不过,由于我想特别将我的Python脚本与Ubuntu Linux集成,所以我的解决方案是结合一个init.d脚本。

#!/bin/bash

WORK_DIR="/var/lib/foo"
DAEMON="/usr/bin/python"
ARGS="/opt/foo/linux_service.py"
PIDFILE="/var/run/foo.pid"
USER="foo"

case "$1" in
  start)
    echo "Starting server"
    mkdir -p "$WORK_DIR"
    /sbin/start-stop-daemon --start --pidfile $PIDFILE \
        --user $USER --group $USER \
        -b --make-pidfile \
        --chuid $USER \
        --exec $DAEMON $ARGS
    ;;
  stop)
    echo "Stopping server"
    /sbin/start-stop-daemon --stop --pidfile $PIDFILE --verbose
    ;;
  *)
    echo "Usage: /etc/init.d/$USER {start|stop}"
    exit 1
    ;;
esac

exit 0

然后在Python中:

import signal
import time
import multiprocessing

stop_event = multiprocessing.Event()

def stop(signum, frame):
    stop_event.set()

signal.signal(signal.SIGTERM, stop)

if __name__ == '__main__':
    while not stop_event.is_set():
        time.sleep(3)

我现在的问题是这种方法是否正确。我需要处理其他信号吗?这样会成为一个“表现良好的Unix守护进程”吗?

2 个回答

11

Rloton的回答很好。这里我稍微调整了一下,因为我花了很多时间在调试上。而且我需要写一个新的回答,这样可以更好地格式化内容。

还有几个我调试了很久才搞明白的要点:

  1. 当出现故障时,首先检查一下 /var/log/upstart/.log 文件。
  2. 如果你的脚本是用 python-daemon 实现的守护进程,你就不要使用 'expect daemon' 这一段。没有 'expect' 也能正常工作。我不知道为什么。(如果有人知道原因,请分享一下!)
  3. 另外,记得不断检查 "initctl status script",确保你的脚本是启动状态(start/running)。(当你更新配置文件时,也要记得重新加载一下)

这是我的版本:

description "My service"
author  "Some Dude <blah@foo.com>"

env PYTHON_HOME=/<pathtovirtualenv>
env PATH=$PYTHON_HOME:$PATH

start on runlevel [2345]
stop on runlevel [016]

chdir <directory>

# NO expect stanza if your script uses python-daemon
exec $PYTHON_HOME/bin/python script.py

# Only turn on respawn after you've debugged getting it to start and stop properly
respawn
90

假设你的守护进程有某种方式可以持续运行(比如事件循环、twisted等等),你可以试试用 upstart

下面是一个假想的Python服务的upstart配置示例:

description "My service"
author  "Some Dude <blah@foo.com>"

start on runlevel [234]
stop on runlevel [0156]

chdir /some/dir
exec /some/dir/script.py
respawn

如果你把这个保存为script.conf到 /etc/init 目录下,你只需要执行一次

$ sudo initctl reload-configuration
$ sudo start script

你可以用 stop script 来停止它。上面的upstart配置的意思是,在重启时启动这个服务,并且如果它崩溃了也会自动重启。

至于信号处理,你的进程应该能够自然地响应 SIGTERM 信号。默认情况下,这个信号会被处理,除非你特别安装了自己的信号处理器。

撰写回答