当前方案
现在可以使用python-daemon作为参考实现PEP 3143(标准守护进程库)。
历史答案
Sander Marechal的代码示例优于原始版本,该版本最初发布于2004年。我曾经为Pyro贡献过一个守护程序,但如果必须重新执行,则可能会使用Sander的代码。
http://pypi.python.org/pypi/python-daemon
更好。更可靠。只需举一个例子:尝试使用python-daemon
启动两次相同的守护进程:会出现一个大而丑陋的错误。而使用Sander的代码:会有一个友好的提示“守护进程已在运行中”。 - Basjquit()
方法。这是它的链接。 - Basj当成为一个表现良好的守护进程时,有许多琐碎的事情需要注意:
防止核心转储(许多守护程序以root身份运行,核心转储可能包含敏感信息)
在chroot
监狱中正确运行
适当设置UID、GID、工作目录、umask和其他进程参数以满足使用情况
放弃提升的suid
、sgid
权限
关闭所有打开的文件描述符,具体排除哪些依赖于使用情况
在已分离的上下文中启动时正确运行,例如init
、inetd
等
为合理的守护程序行为设置信号处理程序,但也根据使用情况确定特定的处理程序
重定向标准流stdin
、stdout
、stderr
,因为守护进程不再具有控制终端
将PID文件处理为协作的咨询锁定,这本身就是一个很麻烦的问题,有许多相互矛盾但有效的处理方式
在进程终止时进行适当的清理
确实成为守护进程而不导致僵尸进程
其中一些是标准的,如经典的Unix文献(《UNIX环境高级编程》作者W. Richard Stevens已故,Addison-Wesley出版,1992年)所述。其他行为,例如流重定向和PID文件处理,是大多数守护程序用户所期望的惯例行为,但不太标准化。
所有这些都包含在PEP 3143“标准守护进程库”规范中。python-daemon参考实现适用于Python 2.7或更高版本以及Python 3.2或更高版本。
这是我用来开发新守护进程应用程序时使用的基本“Howdy World” Python 守护进程。
#!/usr/bin/python
import time
from daemon import runner
class App():
def __init__(self):
self.stdin_path = '/dev/null'
self.stdout_path = '/dev/tty'
self.stderr_path = '/dev/tty'
self.pidfile_path = '/tmp/foo.pid'
self.pidfile_timeout = 5
def run(self):
while True:
print("Howdy! Gig'em! Whoop!")
time.sleep(10)
app = App()
daemon_runner = runner.DaemonRunner(app)
daemon_runner.do_action()
请注意,您需要安装python-daemon
库。您可以通过以下方式进行安装:
pip install python-daemon
只需使用./howdy.py start
启动它,使用./howdy.py stop
停止它。
daemon
模块不是 Python 的标准部分(至少目前还不是)。你需要使用 pip install python-daemon
或其等效命令来安装它。 - Nateio.UnsupportedOperation: File or stream is not seekable.
- alper另一种方法是创建一个普通的、非守护程序化的Python程序,然后使用supervisord外部进行守护。这可以避免很多麻烦,并且具有*nix和语言可移植性。
也许不是对问题的直接回答,但systemd可以用来将您的应用程序作为守护进程运行。以下是一个示例:
[Unit]
Description=Python daemon
After=syslog.target
After=network.target
[Service]
Type=simple
User=<run as user>
Group=<run as group group>
ExecStart=/usr/bin/python <python script home>/script.py
# Give the script some time to startup
TimeoutSec=300
[Install]
WantedBy=multi-user.target
我喜欢这种方法,因为其中的大部分工作已经为你完成,然后你的守护进程脚本就可以与系统的其余部分类似地运行。
systemctl start control.service
即可。 - jimper这个函数将把一个应用程序转化为守护进程:
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尚未支持python 3.x,从邮件列表中可以读到,它可能永远不会支持。因此,我编写了一个新的PEP 3143实现:pep3143daemon
pep3143daemon应该支持至少python 2.6、2.7和3.x
它还包含一个PidFile类。
该库仅依赖于标准库和six模块。
它可以用作python-daemon的替代品。
这里是文档。
我担心 @Dustin 提到的守护进程模块对我不起作用。相反,我安装了python-daemon并使用以下代码:
# filename myDaemon.py
import sys
import daemon
sys.path.append('/home/ubuntu/samplemodule') # till __init__.py
from samplemodule import moduleclass
with daemon.DaemonContext():
moduleclass.do_running() # I have do_running() function and whatever I was doing in __main__() in module.py I copied in it.
> python myDaemon.py
为了完整起见,这里是samplemodule目录的内容:
>ls samplemodule
__init__.py __init__.pyc moduleclass.py
moduleclass.py的内容可以是:
class moduleclass():
...
def do_running():
m = moduleclass()
# do whatever daemon is required to do.