在谷歌上搜索显示x2个代码片段。第一个结果是这个代码配方,它有很多文档和解释,以及下面一些有用的讨论。
然而,另一个代码示例虽然不包含这么多文档,但包含了传递启动、停止和重启等命令的示例代码。它还创建了一个PID文件,可以方便地检查守护进程是否已经在运行等。
这些示例都解释了如何创建守护进程。还有其他需要考虑的事情吗?一个样本比另一个更好吗?为什么?
在谷歌上搜索显示x2个代码片段。第一个结果是这个代码配方,它有很多文档和解释,以及下面一些有用的讨论。
然而,另一个代码示例虽然不包含这么多文档,但包含了传递启动、停止和重启等命令的示例代码。它还创建了一个PID文件,可以方便地检查守护进程是否已经在运行等。
这些示例都解释了如何创建守护进程。还有其他需要考虑的事情吗?一个样本比另一个更好吗?为什么?
当前回答
经过几年的努力和多次尝试(我尝试了这里给出的所有答案,但最后都有一些小缺点),现在我意识到有一种比直接从Python启动、停止和重新启动守护进程更好的方法:使用OS工具。
例如,对于Linux,我不做python myapp start和python myapp stop,而是这样启动应用程序:
screen -S myapp python myapp.py
# CTRL+A, D to detach
或者screen -dmS myapp python myapp.py在一个命令中启动和卸载它。
然后:
screen -r myapp
重新连接到这个终端。进入终端后,可以使用CTRL+C来停止它。
其他回答
虽然你可能更喜欢Python -daemon模块提供的纯Python解决方案,但在libc中有一个daemon(3)函数——至少在BSD和Linux上是这样——它可以做正确的事情。
从python调用它很简单:
import ctypes
ctypes.CDLL(None).daemon(0, 0) # Read the man-page for the arguments' meanings
剩下要做的唯一一件事就是创建(和锁定)pid文件。但你能处理好自己…
YapDi是一个python包。它可用于从脚本内部将python脚本转换为守护进程模式。
这个函数将应用程序转换为守护进程:
import sys
import os
def daemonize():
try:
pid = os.fork()
if pid > 0:
# exit first parent
sys.exit(0)
except OSError as err:
sys.stderr.write('_Fork #1 failed: {0}\n'.format(err))
sys.exit(1)
# decouple from parent environment
os.chdir('/')
os.setsid()
os.umask(0)
# do second fork
try:
pid = os.fork()
if pid > 0:
# exit from second parent
sys.exit(0)
except OSError as err:
sys.stderr.write('_Fork #2 failed: {0}\n'.format(err))
sys.exit(1)
# redirect standard file descriptors
sys.stdout.flush()
sys.stderr.flush()
si = open(os.devnull, 'r')
so = open(os.devnull, 'w')
se = open(os.devnull, 'w')
os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno())
注意python-daemon包,它可以开箱即用地解决daemon背后的许多问题。
它支持的其他特性(来自Debian包描述)包括:
将进程分离到自己的进程组中。 设置适合在chroot中运行的进程环境。 放弃suid和sgid权限。 关闭所有打开的文件描述符。 修改工作目录、uid、gid和umask。 设置适当的信号处理程序。 打开stdin、stdout和stderr的新文件描述符。 管理指定PID锁文件。 注册用于出口处理的清理函数。
在成为一个行为良好的守护进程时,有许多精细的事情需要注意:
prevent core dumps (many daemons run as root, and core dumps can contain sensitive information) behave correctly inside a chroot gaol set UID, GID, working directory, umask, and other process parameters appropriately for the use case relinquish elevated suid, sgid privileges close all open file descriptors, with exclusions depending on the use case behave correctly if started inside an already-detached context, such as init, inetd, etc. set up signal handlers for sensible daemon behaviour, but also with specific handlers determined by the use case redirect the standard streams stdin, stdout, stderr since a daemon process no longer has a controlling terminal handle a PID file as a cooperative advisory lock, which is a whole can of worms in itself with many contradictory but valid ways to behave allow proper cleanup when the process is terminated actually become a daemon process without leading to zombies
其中一些是标准的,如Unix规范文献(已故的W. Richard Stevens所著的《Unix环境中的高级编程》,Addison-Wesley, 1992年)中所述。其他的,如流重定向和PID文件处理,是大多数守护进程用户所期望的常规行为,但不太标准化。
所有这些都包含在PEP 3143“标准守护进程库”规范中。Python -daemon参考实现适用于Python 2.7或更高版本,以及Python 3.2或更高版本。